package com.dahua.messageconsumer;

import com.alibaba.fastjson.JSON;
import com.dahua.common.CommonMethod;
import com.dahua.common.GsonUtils;
import com.dahua.common.config.*;
import com.dahua.common.dao.*;
import com.dahua.common.domain.*;
import com.dahua.common.dto.Control56SmallDTO;
import com.dahua.common.dto.EquipmentFaultSmallDTO;
import com.dahua.common.dto.WithFlag;
import com.dahua.messageconsumer.model.*;
import com.dahua.common.service.LatestSensorStatusService;
import com.dahua.messageconsumer.service.Producer;
import com.dahua.messageconsumer.sql.*;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

@RestController
@Slf4j
public class MessageConsumer {

//    @Autowired
//    SensorDataManager sensorDataManager;
//    @Autowired
//    SensorDataDhMapper sensorDataDhMapper;
//
//    @Autowired
//    EquipmentStatusMapper equipmentStatusMapper;
//
//    @Autowired
//    EquipmentStatusThisMonthMapper equipmentStatusThisMonthMapper;
//
//    @Autowired
//    EquipmentStatusTodayMapper equipmentStatusTodayMapper;
//    @Autowired
//    EquipmentStatusAlldayMapper equipmentStatusAlldayMapper;

//    @Autowired
//    EquipmentFaultMapper equipmentFaultMapper;
//    @Autowired
//    EquipmentFaultDhMapper equipmentFaultDhMapper;

//    @Autowired
//    RuntimeParamMapper runtimeParamMapper;

//    @Autowired
//    LatestFaultMapper latestFaultMapper;

    @Autowired
    FaultMapper faultMapper;

    @Autowired
    FaultInfoMapper faultInfoMapper;

    @Autowired
    FaultallMapper faultallMapper;

    @Autowired
    private StationMapper stationMapper;
    @Autowired
    private LineMapper lineMapper;
    @Autowired
    private EquipmentMapper equipmentMapper;
//    @Autowired
//    private LatestEquipmentStatusDao latestEquipmentStatusDao;

    @Autowired
    private WorkbillDao workbillDao;
    @Autowired
    Control56Mapper control56Mapper;
    @Autowired
    Control56wbMapper control56wbMapper;
    @Autowired
    SensorMapper sensorMapper;
    @Autowired
    EquipmentpartsMapper equipmentpartsMapper;
    @Autowired
    PartMapper partMapper;
    @Autowired
    PartgroupDao partgroupDao;
    @Autowired
    Control56configMapper control56configMappper;

    @Autowired
    LatestSensorStatusService latestSensorStatusService;

    @Autowired
    Producer producer;

    @Autowired
    ClientConfigparamsVersionDao clientConfigparamsVersionDao;
    @Autowired
    ClientConfigsDao clientConfigsDao;
    @Autowired
    ClientParamsDao clientParamsDao;
    @Autowired
    ClientAiParamsDao clientAiParamsDao;
    @Autowired
    ClientVibParamsDao clientVibParamsDao;
    @Autowired
    ClientPublicParamsDao clientPublicParamsDao;
    @Autowired
    ClientDmParamsDao clientDmParamsDao;

//    @Autowired
//    ClientConfigparamsVersionUploadDao clientConfigparamsVersionUploadDao;
//    @Autowired
//    ClientConfigsUploadDao clientConfigsUploadDao;
//    @Autowired
//    ClientParamsUploadDao clientParamsUploadDao;
//    @Autowired
//    ClientAiParamsUploadDao clientAiParamsUploadDao;
//    @Autowired
//    ClientVibParamsUploadDao clientVibParamsUploadDao;
    @Autowired
    ClientPublicParamsUploadDao clientPublicParamsUploadDao;
//    @Autowired
//    ClientDmParamsUploadDao clientDmParamsUploadDao;

//    @Autowired
//    VersionInfoDao versionInfoDao;
//    @Autowired
//    DataLogMapper dataLogMapper;

    @Autowired
    EquipmentData4CheckMapper equipmentData4CheckMapper;
//    @Autowired
//    SensorDataMapper sensorDataMapper;

    @Autowired
    SyncMessageMapper syncMessageMapper;

//    @Autowired
//    ClientAiVibPublicDmUploadTimeDao clientAiVibPublicDmUploadTimeDao;

    //    @Autowired
    //    private ElevatorMapper elevatorMapper;

    @Autowired
    EquipmentSensorDataFileLevelTimeMapper equipmentSensorDataFileLevelTimeMapper;

    @Autowired
    DictDetailMapper dictDetailMapper;

    @Autowired
    UpgradeLogMapper upgradeLogMapper;

    public static String hitachi = "hitachi";
    public static String configsName = "configs";
    public static String params = "params";

    public static volatile Map<Integer, String> equipmentMessage = new HashMap<>();
    public static volatile Map<Integer, String> equipmentMessageAll = new HashMap<>();
    public static volatile Map<Integer, String> wrongFileInfo = new HashMap<>();

    public static volatile Map<Integer, String> statusTimeRequest = new HashMap<>(); // 请求
    public static volatile Map<Integer, String> statusTimeResult = new HashMap<>(); // 接收结果
    public static volatile Map<Integer, String> db2serverInfo = new HashMap<>(); // 接收结果

    public static volatile Map<Integer, LocalDateTime> lastSensorDataTimes = new ConcurrentHashMap<>();
    public static volatile Map<Integer, Boolean> lastHasFault = new ConcurrentHashMap<>(); // 用于减少数据库操作

    // 用于控制检修期间的故障等不统计
    public static volatile Map<Integer, Integer> isMaintainenceStatus = new ConcurrentHashMap<>();
    public static volatile Map<Integer, Boolean> needResetTime4CheckMaintainence = new ConcurrentHashMap<>();
    public static volatile Map<Integer, LocalDateTime> NormalTimeAterMaintainence = new ConcurrentHashMap<>();

    public static volatile Map<Integer, LocalDateTime> NormalTimeAterMaintainence2 = new ConcurrentHashMap<>();
    public static volatile Map<Integer, LocalDateTime> latestData_56Time = new ConcurrentHashMap<>();

    public static volatile Map<Integer, Double> lastCurrent1301 = new ConcurrentHashMap<>();
    public static volatile Map<Integer, Double> lastCurrent2302 = new ConcurrentHashMap<>();

    // 如果master重启，部分故障还是重发上来。这里增加记录防止重复记录故障。-- 按日立要求
    public static volatile Map<Integer, Control56> lastControl56s = new ConcurrentHashMap<>();
    public static volatile Map<Integer, Elevator> lastElevators = new ConcurrentHashMap<>();

    //
    public static List<Sensor> sensors = new ArrayList<>();

    public static LocalDateTime wsTime = LocalDateTime.now();
    public static LocalDateTime wsTime2 = LocalDateTime.now();

    public static volatile Map<Integer, List<EquipmentSensorDataFileLevelTime>> dataFileLevelTimes = new ConcurrentHashMap<>();

    // 2021-09-26 Miss Lee 人为格式化数据去除故障增加合理性
    // -- 1201,1202,1203,1205,1206,1401,1402,1501,1502,2206
    // 梯号	 下机房噪声	 下机房	 减速箱油温1	减速箱油温2 	环境温度	左扶手带温度	右扶手带温度	 	左位移	右位移
    @Value("${data.reformat}")
    private String reformatData;
    @Value("${data.reformatfault}")
    private Integer reformatfault;
    @Value("${data.web56}")
    private Integer web56;
    @Value("${data.savesensordataxx}")
    private Integer savesensordataxx;
    @Value("${data.saveenergy}")
    private Integer saveenergy; // 根据电流计算能耗
    @Value("${data.energyxishu}")
    private Double energyxishu; // 根据电流计算能耗
    @Value("${data.volt}")
    private Double volt; // 380V
    @Value("${data.maxcurrent}")
    private Integer maxcurrent; // 有可能传感器故障

    // 故障邮件（仅内网）
    @Value("${data.websocket3}")
    private String websocket3;
    @Value("${data.sqltrytimes}")
    private Integer sqltrytimes;

    public static volatile ReformatData[] reformatSensorIds = new ReformatData[]{
        new   ReformatData(1501, 7d, 2d, 1502, 55d, 95d),
        new   ReformatData(1502, 60d, 20d, 0, 55d, 95d),
//        new   ReformatData(1205, 39.9d, 6d, 0),
//        new   ReformatData(2206, 41.98d, 3d, 0),
//        new   ReformatData(1203, 28.5d, 8d, 0),
//        new   ReformatData(1201, 0d, 2.2d, 1203),
//        new   ReformatData(1202, 0d, 2.3d, 1203),
        new   ReformatData(1401, 0d, 0.15d, 0, 0d, 1d),
        new   ReformatData(1402, 0d, 0.14d, 0, 0d, 1d),
        new   ReformatData(1301, 20d, 10d, 0, 0d, 30d),
        new   ReformatData(2302, 20d, 10d, 0, 0d, 30d),
//        new   ReformatData(1206, 41.5d, 4d, 0),
        new   ReformatData(8888, 100d, 4d, 0, 0d, 100d),
    };

    public static volatile String diskUsageInfo="";
    // isreceiver = 1: 只接收，送队列 ； 0：正常处理
    //    @Value("${data.isreceiver}")
    //    private Integer isreceiver;

    @Value("${data.upgradeserverfromdh}")
    private Integer upgradeserverfromdh;

    @Value("${data.queueofdata}")
    private Integer queueofdata;

    @Value("${data.queueof56}")
    private Integer queueof56;

    @Value("${data.queueofiot}")
    private Integer queueofiot;

    @Value("${data.send2iot}")
    private Integer send2iot;

    @Value("${data.queueofequipmentfault}")
    private Integer queueofequipmentfault;

    // 只记录 RMS 为  null，方便排查
    public static volatile Map<String, LocalDateTime> rmsNullLIst = new ConcurrentHashMap<>();

    @Value("${data.send2queue2}")
    private Integer send2queue2; // 转发部分数据到queue2
    @Value("${data.euqipmentids2queue2}")
    private String euqipmentids2queue2; // 只转发这些id

    @Value("${data.queue2ofdata}")
    private Integer queue2ofdata;

    @Value("${data.queue2of56}")
    private Integer queue2of56;

    @Value("${data.queueofsql}")
    private Integer queueofsql;
    @Value("${data.queueofsqlfirst}")
    private Integer queueofsqlfirst;
    @Value("${data.queueofsqleqf}")
    private Integer queueofsqleqf;

    @Value("${data.queue2ofequipmentfault}")
    private Integer queue2ofequipmentfault;
    @Value("${data.sendElevator2queue2}")
    private Integer sendElevator2queue2; // 转发直梯数据到queue2

    @Value("${data.Hitachi.brandid}")
    private Integer hitachiBrandid;

    @Value("${data.Hitachi.GRbrandid}")
    private Integer GRbrandid;

    @Value("${data.SanLing.brandid}")
    private Integer SLbrandid;
    @Value("${data.Otis.brandid}")
    private Integer otisBrandid;


    @Value("${data.FTZT.brandids}")
    private String brandids;
    @Value("${data.FTZT.beginchars}")
    private String beginchars;
    @Value("${data.FT.up}")
    private String up;
    @Value("${data.FT.down}")
    private String down;
    @Value("${data.FT.normalstop}")
    private String normalstop;
    @Value("${data.FT.maintainence}")
    private String maintainence;
    @Value("${data.FT.numofcode}")
    private String numofcode;
    @Value("${data.ZT.numofcode}")
    private String numofcodeZT;
    @Value("${data.sampleseconds4zt}")
    private Integer sampleseconds4zt;


    @Value("${data.FT.allruncodes}")
    private String allruncodes;
    @Value("${data.FT.allstopcodes}")
    private String allstopcodes;

    @Value("${data.FT.runningtimecounttype}")
    private Integer runningtimecounttypeSetting;
    private int runnintTimeCountType;
    @Value("${data.ZT.runningtimecounttype}")
    private Integer runningtimecounttypeSettingZT;
    private int runnintTimeCountTypeZT;

    private Map<Integer, String> brandIdBeginChars = new HashMap<>();
    private Map<Integer, Set<String>> brandIdUpCodes = new HashMap<>();
    private Map<Integer, Set<String>> brandIdDownCodes = new HashMap<>();
    private Map<Integer, Set<String>> brandIdNormalStopCodes = new HashMap<>();
    private Map<Integer, Set<String>> brandIdMaintainenceCodes = new HashMap<>();
    private Map<Integer, Integer> brandIdNumOfCodes = new HashMap<>();
    private Map<Integer, Integer> brandIdNumOfCodesZT = new HashMap<>();


    public static volatile Set<Integer> euqipmentids2queue2Set = new HashSet<>();
    public static volatile boolean sendAllid2queue2 = false;

    public static volatile Set<String> control56_fault_statuscodeSet = new HashSet<>();

    private Integer control56_fault_leveldh = 3;
    private Integer control56_fault_level = 1;
    private Integer control56_fault_partcode = 9999;
    private String control56_fault_remark = "B";
    private String control56_fault_faultclass = "二类";

    @Value("${web.sendEqf2Web}")
    private Integer sendEqf2Web;

    @Value("${data.create.workbill}")
    private Integer create_workbill;

    @PostMapping("/data")
    //public Map syncData(@RequestBody String base64Str) {
    public Map syncData(@RequestBody byte[] sendData, HttpServletRequest request) {
        Map respBody = new HashMap();
        if (!checkInitialOK(respBody)) {
            return respBody;
        }

        try {
            // 用于打印通讯时间和解密前后内容
            printInfo(sendData);

            //String mapStr = new String(Base64Utils.decodeFromString(base64Str.replace("\r\n", "")));
            String mapStr = unCompress(sendData);
            if (PublicVars.printCommunicationInfo == 1 || PublicVars.printEncryptionData == 1) {
                log.info("解密解压后长度：" + mapStr.length());
                log.info("解密解压后内容：" + mapStr);
            }

            Map<String, String> jsonMap = GsonUtils.getGson().fromJson(mapStr, new TypeToken<Map<String, String>>() {
            }.getType());
            String uploadStatusJson = jsonMap.get("uploadStatus");
            if (uploadStatusJson != null) {
                int eqid1 = syncUploadStatus(uploadStatusJson);
                //                if (isreceiver == 1) {
                //                    producer.sendMessage(eqid1 % queueofdata, producer.QUEUE_EQDATA_CONSUMER, sendData);
                //                    //producer.sendMessageToTopic(producer.TOPIC_EQDATA_CONSUMER, eqid1, sendData);
                //                    respBody.put("errorCode", 0);
                //                    respBody.put("errorMsg", "");
                //                    return respBody;
                //                }
                respBody.put("ftpAllFiles", buildFtpAllFilesList(eqid1));

                if (PublicVars.isPortalWithData != 1) {
                    producer.sendMessage(eqid1 % queueofdata, producer.QUEUE_EQDATA_PORTAL, sendData);
                    // no IOT
                    //producer.sendMessageToTopic(producer.TOPIC_EQDATA, eqid1, sendData);
                }
                if (sendAllid2queue2 || euqipmentids2queue2Set.contains(eqid1)) {
                    producer.sendMessage2(eqid1 % queue2ofdata, producer.QUEUE_EQDATA_PORTAL, sendData);
                }

                respBody.put("errorCode", 0);
                respBody.put("errorMsg", "");
                return respBody;
            }
            String reportNoDataJson = jsonMap.get("reportNoData");
            if (reportNoDataJson != null) {
                int eqid1 = reportNoData(reportNoDataJson);
                if (eqid1 <= 0) {
                    log.error("缺少 设备id");

                    respBody.put("errorCode", 1010);
                    respBody.put("errorMsg", "缺少 设备id");
                } else {
                    respBody.put("errorCode", 0);
                    respBody.put("errorMsg", "");
                }
                //                if (isreceiver == 1) {
                //                    producer.sendMessage(eqid1 % queueofdata, producer.QUEUE_EQDATA_CONSUMER, sendData);
                //                    //producer.sendMessageToTopic(producer.TOPIC_EQDATA_CONSUMER, eqid1, sendData);
                //                    respBody.put("errorCode", 0);
                //                    respBody.put("errorMsg", "");
                //                    return respBody;
                //                }


                if (PublicVars.isPortalWithData != 1) {
                    producer.sendMessage(eqid1 % queueofdata, producer.QUEUE_EQDATA_PORTAL, sendData);
                    // no IOT
                    //producer.sendMessageToTopic(producer.TOPIC_EQDATA, eqid1, sendData);
                }
                if (sendAllid2queue2 || euqipmentids2queue2Set.contains(eqid1)) {
                    producer.sendMessage2(eqid1 % queue2ofdata, producer.QUEUE_EQDATA_PORTAL, sendData);
                }
                return respBody;
            }
            String eqDataJson = jsonMap.get("equipmentData");
            if (eqDataJson == null) {
                return respBody;
            }
            List<EquipmentStatus> equipmentStatusList = GsonUtils.getGson().fromJson(eqDataJson, new TypeToken<List<EquipmentStatus>>() {
            }.getType());
            int equipmentId = 0;

            //            if (isreceiver == 1) {
            //                if(equipmentStatusList != null && !equipmentStatusList.isEmpty()) {
            //                    producer.sendMessage(equipmentStatusList.get(0).getEq_ID() % queueofdata, producer.QUEUE_EQDATA_CONSUMER, sendData);
            //                    //producer.sendMessageToTopic(producer.TOPIC_EQDATA_CONSUMER, equipmentStatusList.get(0).getEq_ID(), sendData);
            //                }
            //                respBody.put("errorCode", 0);
            //                respBody.put("errorMsg", "");
            //                return respBody;
            //            }


            // 2021-09-26 Miss Lee
            DoReformatData(equipmentStatusList);

            int printFirst = 0;
            // 缓存 Map<String, FaultInfo> faultInfoMap = faultInfoMapper.getAllFaultInfoMap();
            for (EquipmentStatus equipmentStatus : equipmentStatusList) {
                QueueTimes.countDataP1();
                // 防止重复
                if (equipmentStatus.getTime() != null && equipmentStatus.getTime().equals(lastSensorDataTimes.get(equipmentStatus.getEq_ID()))) {
                    continue;
                }

                // 0 -- 5
                if (equipmentStatus.getStatus() == null || equipmentStatus.getStatus() < 0 || equipmentStatus.getStatus() > 5) {
                    log.error("缺少 Status字段或者取值不符(0--5之间)");

                    respBody.put("errorCode", 1012);
                    respBody.put("errorMsg", "缺少 Status字段或者取值不符(0--5之间)");
                    return respBody;
                    // throw new RuntimeException("缺少 Status字段或者取值不符(0--5之间)");
                }
                // 对于 缓慢 status=4 ，先记录
                boolean isSlowRun = false;
                if (equipmentStatus.getStatus() == 4) {
                    isSlowRun = true;
                }

                if (equipmentStatus.getEq_ID()==null || equipmentStatus.getEq_ID() <= 0) {
                    log.error("缺少 设备id");

                    respBody.put("errorCode", 1010);
                    respBody.put("errorMsg", "缺少 设备id");
                    return respBody;
                    //throw new RuntimeException("缺少 设备id");
                }
                if (equipmentStatus.getTime() == null) {
                    log.error("缺少 数据时间Time");

                    respBody.put("errorCode", 1013);
                    respBody.put("errorMsg", "缺少 数据时间Time");
                    return respBody;
                    // throw new RuntimeException("缺少 数据时间Time");
                }

                // 这几个字段收到的时候是NULL，先设置
                equipmentStatus.setMQ_Send_Status(0);
                equipmentStatus.setServer_Send_Status(0);
                equipmentStatus.setEndTime(equipmentStatus.getTime());
                equipmentStatus.setPeriod(PublicVars.sampleseconds); // 改为秒.默认20秒
                equipmentStatus.setTotalTimes(1);

                //新增的 lineid, stationid, deptid, 根据Eq_id --> Station --> Line
                equipmentStatus.setDataServerId(PublicVars.dataServerId);
                equipmentStatus.setDataId(0L);

                // 维保判断用
                if (    isMaintainenceStatus.containsKey(equipmentStatus.getEq_ID())) {
                    if ( !latestData_56Time.containsKey(equipmentStatus.getEq_ID())
                            ||  latestData_56Time.get(equipmentStatus.getEq_ID()).isBefore(equipmentStatus.getTime()) )
                    latestData_56Time.put(equipmentStatus.getEq_ID(), equipmentStatus.getTime());
                }

                Equipment e1 = PublicVars.getEquipment(equipmentMapper,equipmentStatus.getEq_ID());
                if (e1!=null){
                    equipmentStatus.setDeptid(e1.getDeptid());
                    equipmentStatus.setLineid(e1.getLineid());
                    equipmentStatus.setStation_ID(e1.getStationId());
                    equipmentStatus.setBrandid(e1.getBrandid());
                    equipmentStatus.setBk2(e1.getBk2());  // 设备类型
                    equipmentStatus.setBk5(e1.getBk5());  // 设备分级
                } else {
                    log.error(String.format("服务器端尚未配置该设备id: %d , ip: %s (configs配置错误)", equipmentStatus.getEq_ID(), request.getRemoteAddr()));

                    respBody.put("errorCode", 1000);
                    respBody.put("errorMsg", String.format("服务器端尚未配置该设备id: %d , ip: %s (configs配置错误)", equipmentStatus.getEq_ID(), request.getRemoteAddr()));
                    return respBody;
                    // throw new RuntimeException("服务器端尚未配置该设备id : " + equipmentStatus.getEq_ID());
                }
                // 提前检查数据有效性
                if (equipmentStatus.getSensorData() != null && !equipmentStatus.getSensorData().isEmpty()) {
                    for (SensorData sensorData : equipmentStatus.getSensorData()) {
                        // 广日可能乱传测点
                        if (sensorData.getVib_Sensor_No() == null || sensorData.getVib_Sensor_No() <= 0) {
                            log.error("数据不合法，缺少测点id");

                            respBody.put("errorCode", 1011);
                            respBody.put("errorMsg", "数据不合法，缺少测点id");
                            return respBody;
                            // throw new RuntimeException("数据不合法，缺少测点id");
                        }
                        Sensor s1 = PublicVars.getSensorinfo(sensorMapper,sensorData.getVib_Sensor_No());
                        if (s1 == null) {
                            log.error(String.format("服务器端尚未配置该测点id: %d , ip: %s (configs配置错误)", sensorData.getVib_Sensor_No(), request.getRemoteAddr()));

                            respBody.put("errorCode", 1001);
                            respBody.put("errorMsg", String.format("服务器端尚未配置该测点id: %d , ip: %s (configs配置错误)", sensorData.getVib_Sensor_No(), request.getRemoteAddr()));
                            return respBody;
                            //throw new RuntimeException("服务器端尚未配置该测点id : " + sensorData.getVib_Sensor_No());
                        }
                    }
                }

                if (PublicVars.printCommunicationInfo == 1 && printFirst == 0) {
                    printFirst++;
                    if (PublicVars.printCommunicationInfo == 1) {
                        log.info("数据时间：" + equipmentStatus.getTime());
                    }
                }

                int sampleseconds = getSampleSeconds(equipmentStatus.getStation_ID(), equipmentStatus.getLineid());
                if ("ZT".equals(e1.getBk2())) {
                    sampleseconds = sampleseconds4zt; // BJ 直梯也是预警系统
                } else {
                    if (sampleseconds == -1) {
                        log.error(String.format("服务器端尚未配置该车站id: %d , ip: %s (configs配置错误)", equipmentStatus.getStation_ID(), request.getRemoteAddr()));

                        respBody.put("errorCode", 1002);
                        respBody.put("errorMsg", String.format("服务器端尚未配置该车站id: %d , ip: %s (configs配置错误)", equipmentStatus.getStation_ID(), request.getRemoteAddr()));

                        return respBody;
                    }
                    if (sampleseconds == -2) {
                        log.error(String.format("服务器端尚未配置该线路id: %d , ip: %s (configs配置错误)", equipmentStatus.getLineid(), request.getRemoteAddr()));

                        respBody.put("errorCode", 1003);
                        respBody.put("errorMsg", String.format("服务器端尚未配置该线路id: %d , ip: %s (configs配置错误)", equipmentStatus.getLineid(), request.getRemoteAddr()));

                        return respBody;
                    }
                    if (sampleseconds == 0) {
                        log.error("服务器端尚未配置默认采样时间");

                        respBody.put("errorCode", 1004);
                        respBody.put("errorMsg", "服务器端尚未配置默认采样时间");
                        return respBody;
                    }
                }
                int samplesecondsBak = sampleseconds;
                // 参考HongKong，新计算方法
                if (CommonMethod.isFT(e1.getBk2())) {
                    if (runnintTimeCountType == RunningTimeCoutType.BYCONTROL56) {
                        sampleseconds = PublicVarsTimeDay.getPeriodBy56(equipmentStatus, sampleseconds, control56Mapper);
                    } else if (runnintTimeCountType == RunningTimeCoutType.BY1601) {
                        sampleseconds = PublicVarsTimeDay.getPeriodByRMS1601(equipmentStatus, sampleseconds);
                    } else {  // if (runnintTimeCountType == RunningTimeCoutType.BYSTATUS012345) {
                        sampleseconds = PublicVarsTimeDay.getPeriodByStatus012345(equipmentStatus, sampleseconds);
                    }
                } else {
                    if (runnintTimeCountTypeZT == RunningTimeCoutType.BYCONTROL56) {
                        sampleseconds = PublicVarsTimeDay.getPeriodBy56(equipmentStatus, sampleseconds, control56Mapper);
                    } else if (runnintTimeCountTypeZT == RunningTimeCoutType.BY1601) {
                        sampleseconds = PublicVarsTimeDay.getPeriodByRMS1601(equipmentStatus, sampleseconds);
                    } else {  // if (runnintTimeCountType == RunningTimeCoutType.BYSTATUS012345) {
                        sampleseconds = PublicVarsTimeDay.getPeriodByStatus012345(equipmentStatus, sampleseconds);
                    }
                }
                equipmentStatus.setPeriod(sampleseconds <= 0 ? samplesecondsBak : sampleseconds); // PublicVars.sampleseconds

                if (isSlowRun && saveenergy == 1) {
                    countEnergy4SlowRun(equipmentStatus);
                }

                //记录 , 防止因为通讯返回故障导致重发 --> 原纪录sensordata完毕才纪录的。改为放到这里。
                // 一般情况下 到这一步后不会再有问题。
                lastSensorDataTimes.put(equipmentStatus.getEq_ID(), equipmentStatus.getTime());

                equipmentId = equipmentStatus.getEq_ID();
                boolean hasFault = false;
                Map<Integer, WithFlag<SensorStatus>> sensorStatusMap = new HashMap<>();
                latestSensorStatusService.fillSensorStatusMap(sensorStatusMap, equipmentId, WithFlag.FLAG_DELETE, equipmentStatus.getSensorData());

                //latestFaultMapper.deleteLatestFaultByStationIdAndEqId(equipmentStatus.getStation_ID(), equipmentId);
                int min_dia_level = 999;
                int faultid = 1;
                if (equipmentStatus.getFaults() != null && !equipmentStatus.getFaults().isEmpty()) {
                    for (Fault fault : equipmentStatus.getFaults()) {
                        if (StringUtils.isEmpty(fault.getDia_Rlt())) {
                            continue;
                        }

                        // dataServerId
                        fault.setDataServerId(equipmentStatus.getDataServerId());
                        fault.setLineid(equipmentStatus.getLineid());
                        fault.setStation_ID(equipmentStatus.getStation_ID());
                        fault.setDeptid(equipmentStatus.getDeptid());

                        if (fault.getEq_ID() == null) // 广日可能不传这2个，使用header
                            fault.setEq_ID(equipmentStatus.getEq_ID());
                        if (fault.getTime() == null)
                            fault.setTime(equipmentStatus.getTime());

                        fault.setDataId(0L);
                        fault.setBk1id(0);
                        fault.setBk2id(0L);
                        fault.setBk3id(0L);

                        fault.setBk2(e1.getBk2()); // 设备类型
                        fault.setBk5(e1.getBk5()); // 设备分级

                        //新增的 level
                        FaultInfo f1 = PublicVars.getFaultinfo(faultInfoMapper,fault.getDia_Rlt());
                        if (f1 == null) {
                            if (PublicVars.isPortalWithData == 1) {
                                DataLog log = new DataLog();
                                log.setCreate_time(LocalDateTime.now());
                                log.setDescription("预警类代码未定义");
                                log.setMethod(equipmentStatus.getEq_ID().toString());
                                log.setParams(fault.getDia_Rlt());
                                log.setTime(1L);
                                log.setLog_type("FAULT");
                                log.setUsername("");
                                DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                                log.setException_detail(dtf2.format(log.getCreate_time())); // recent time
                                // 2024-05-01 改为缓存
//                                if (dataLogMapper.update(log) <= 0) {
//                                    dataLogMapper.insert(log);
//                                }
                                DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                                dataTypeAndContent.setDataType(SQLDataType.DATA_LOG);
                                dataTypeAndContent.setDataLog(log);// 与eqId无关放入最大队列
                                producer.sendSqlMessage(queueofsql - 1, producer.QUEUE_SQL, JSON.toJSONString(dataTypeAndContent));
                            }
                            continue;
                        }

                        fault.setDialevel(f1.getDia_Level());

                        // 取最小的。
                        if (min_dia_level > f1.getDia_Level()) min_dia_level = f1.getDia_Level();

                        fault.setBk1(f1.getFaultclass()); // 故障分类

                        //新增加的几个字段：品牌、分类等
                        fault.setEquipmentbrandid(e1.getBrandid());

                        // 是否有合法的传感器id
                        Sensor sensor = PublicVars.getSensorinfo(sensorMapper,f1.getPartcode());
                        if (sensor == null) {
                            // 2021-04-02 bug: 如果 故障库没有配置 sensorid，下面 putSensorStatus： null pointer exception (int 基本类型)
                            DataLog log = new DataLog();
                            log.setCreate_time(LocalDateTime.now());
                            log.setDescription("故障未设置测点");
                            log.setMethod(equipmentStatus.getEq_ID().toString());
                            log.setParams(fault.getDia_Rlt());
                            log.setTime(1L);
                            log.setLog_type("FAULT");
                            log.setUsername("");
                            DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                            log.setException_detail(dtf2.format(log.getCreate_time())); // recent time
                            // 2024-05-01 改为缓存
//                            if (dataLogMapper.update(log) <= 0) {
//                                dataLogMapper.insert(log);
//                            }
                            DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                            dataTypeAndContent.setDataType(SQLDataType.DATA_LOG);
                            dataTypeAndContent.setDataLog(log);// 与eqId无关放入最大队列
                            producer.sendSqlMessage(queueofsql - 1, producer.QUEUE_SQL, JSON.toJSONString(dataTypeAndContent));

                            continue;
                        }

                        fault.setSensorid(sensor.getID());
                        fault.setBk3(getFaultRMS(equipmentStatus,sensor.getID())); //记录RMS方便展示
                        fault.setSensortype(sensor.getSensor_type());
                        fault.setPartgroupid(sensor.getPartgroupid());
                        // 继续找设备部件+部件
                        Equipmentparts equipmentparts =PublicVars.getEquipmentpartsInfo(equipmentpartsMapper,fault.getEq_ID(),fault.getSensorid());
                        if (equipmentparts!=null){
                            fault.setPartid(equipmentparts.getPartid());
                            Part part = PublicVars.getPartinfo(partMapper,equipmentparts.getPartid());
                            if (part !=null){
                                fault.setPartbrandid(part.getBrandid());
                                fault.setSupplierid(part.getSupplierid());
                            }
                        }

                        Boolean isInsert = saveFault(fault, false, sampleseconds);
                        //if (isInsert != null && isInsert) {
                            latestSensorStatusService.putSensorStatus(sensorStatusMap, fault);
                        //}

                        //不再 auto_increment
                        fault.setID(fault.getEq_ID()*100L + faultid);
//                        if (latestFaultMapper.updateLatestFault(fault) <= 0) {
//                            latestFaultMapper.insertLatestFault(fault);
//                        }
                        // 2024-05-01 改为缓存
                        DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                        dataTypeAndContent.setDataType(SQLDataType.LATEST_FAULT_INSERT_UPDATE);
                        dataTypeAndContent.setFault(fault);
                        producer.sendSqlMessage(fault.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));

                        faultid++;

                        hasFault = true;

                        publishLatestFault(fault);
                    }
                }
                if (hasFault) {
                    lastHasFault.put(equipmentId, hasFault);

                    // latestFaultMapper.deleteLatestFaultByEqIdAndId(equipmentId, equipmentId * 100L + faultid);
                    // 2024-05-01 改为缓存
                    DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                    dataTypeAndContent.setDataType(SQLDataType.LATEST_FAULT_DELETE);
                    dataTypeAndContent.setLatestFaultDeleteId(new LatestFaultDeleteId(equipmentId, equipmentId * 100L + faultid));
                    producer.sendSqlMessage(equipmentId % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));

                    publishDeleteLatestFault(equipmentStatus.getDataServerId(), equipmentId, equipmentId * 100L + faultid);
                }

                if (equipmentStatus.getSensorData() != null && !equipmentStatus.getSensorData().isEmpty()) {

                    // 不再使用 equipmentData4Check 机制.上面已经有了时间纪录。不会再重复
                    /*
                    if (savesensordataxx == 1) { // 队列处理不过来。线网暂时不记录 分表数据
                        // 是否存在不完整的数据 ？ 正常情况下不应该有
                        List<EquipmentData4Check> equipmentData4Checks = equipmentData4CheckMapper.getAllEquipmentData4ChecksByEquipmentid(equipmentId);
                        if (equipmentData4Checks != null && !equipmentData4Checks.isEmpty()) {
                            for (EquipmentData4Check item : equipmentData4Checks) {
                                for (Sensor sensor : sensors) {
                                    if ("A".equalsIgnoreCase(sensor.getSensor_type()) == false)
                                        continue;

                                    try {
                                        sensorDataMapper.deleteByEqidAndTime(equipmentId, sensor.getID(), item.getDatatime());
                                    } catch (Exception e2) {
                                        log.error(e2.getMessage());
                                    }
                                }
                            }
                            equipmentData4CheckMapper.deleteByEquipmentid(equipmentId);
                        }
                    }

                    if (savesensordataxx == 1) { // 队列处理不过来。线网暂时不记录 分表数据
                        equipmentData4CheckMapper.insert(equipmentId, equipmentStatus.getTime(), LocalDateTime.now());
                    }
                    */

                    // 新的SensorData:工控机没有这三个温度字段了 Temp_Val1 / 2 /3,
                    // 为了减少服务器端改动图谱改动，服务器保留着三个字段。在这个调用中自行计算。
                    calculateTemperature(equipmentStatus);
                    for (SensorData sensorData : equipmentStatus.getSensorData()) {

                        if (sensorData.getRMS() == null ){
                            log.error("RMS字段不能为 null");

                            rmsNullLIst.put(equipmentStatus.getEq_ID() + "-" + sensorData.getVib_Sensor_No(), sensorData.getTime());

                            respBody.put("errorCode", 1005);
                            respBody.put("errorMsg", "RMS字段不能为 null");
                            return respBody;
                        }

                        sensorData.setUpload_Status(null);

                        if (sensorData.getEq_ID() == null) // 广日可能不传这3个，使用header
                            sensorData.setEq_ID(equipmentStatus.getEq_ID());
                        if (sensorData.getStation_ID() == null)
                            sensorData.setStation_ID(equipmentStatus.getStation_ID());
                        if (sensorData.getTime() == null)
                            sensorData.setTime(equipmentStatus.getTime());

                        if (sensorData.getVib_Sensor_No() == 1601 && Math.abs(sensorData.getRMS()) > 0.01 ) {
                            sendRms1601(equipmentStatus.getEq_ID(), Math.abs(sensorData.getRMS()));
                        }
                        if (savesensordataxx == 1) { // 队列处理不过来。线网暂时不记录 分表数据

                            // sensorDataManager.saveSensorData(sensorData);
                            // 2024-05-01 改为缓存
                            DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                            dataTypeAndContent.setDataType(SQLDataType.SENSOR_DATA);
                            dataTypeAndContent.setSensorData(sensorData);
                            producer.sendSqlMessage(sensorData.getEq_ID() % queueofsql, producer.QUEUE_SQL, JSON.toJSONString(dataTypeAndContent));

                            if (sensorData.getVib_Sensor_No().equals(1102)) {
                                checkAndSetDataFileLevelTimes(sensorData);
                            }
                        }
                        // 能耗  -- 1301	电机1电流 ， 2302	电机2电流
                        if (!isSlowRun && saveenergy == 1
                                && sensorData.getVib_Sensor_No() != null
                                && sensorData.getRMS() !=null) {
                            Double energy = 0d;
                            double avgRms = 0;
                            if (sensorData.getVib_Sensor_No() == 1301 && Math.abs(sensorData.getRMS()) > 0.01 ) {
                                Double last = lastCurrent1301.get(sensorData.getEq_ID());
                                if (last == null)
                                    last = 0d;
                                avgRms = (last + Math.abs(sensorData.getRMS())) / 2;
                                energy = 1.732 * volt * ( avgRms > maxcurrent ? last : avgRms ) * energyxishu * sampleseconds / 3600.0 / 1000;
                                lastCurrent1301.put(sensorData.getEq_ID(), Math.abs(sensorData.getRMS()));
                            }
                            if (sensorData.getVib_Sensor_No() == 2302 && Math.abs(sensorData.getRMS()) > 0.01 ) {
                                Double last = lastCurrent2302.get(sensorData.getEq_ID());
                                if (last == null)
                                    last = 0d;
                                avgRms = (last + Math.abs(sensorData.getRMS())) / 2;
                                energy = 1.732 * volt * (avgRms > maxcurrent ? last : avgRms ) * energyxishu * sampleseconds / 3600.0 / 1000;
                                lastCurrent2302.put(sensorData.getEq_ID(), Math.abs(sensorData.getRMS()));
                            }
                            //放入队列。让另一个线程来计算和处理。以避免冲突
                            if (energy > 0.0001) {
                                Consumeenergy consumeenergy = new Consumeenergy();
                                consumeenergy.setLineid(equipmentStatus.getLineid());
                                consumeenergy.setStationid(equipmentStatus.getStation_ID());
                                consumeenergy.setEquipmentid(sensorData.getEq_ID());
                                consumeenergy.setDeptid(equipmentStatus.getDeptid());
                                consumeenergy.setBk2(equipmentStatus.getBk2());
                                consumeenergy.setBk5(equipmentStatus.getBk5());
                                consumeenergy.setValue(energy);
                                consumeenergy.setTime(LocalDateTime.of(sensorData.getTime().getYear(), sensorData.getTime().getMonthValue(), sensorData.getTime().getDayOfMonth(), sensorData.getTime().getHour(), 0));//转为小时
                                consumeenergy.setYyyy(sensorData.getTime().getYear());
                                consumeenergy.setYyyymm(sensorData.getTime().getYear() * 100 + sensorData.getTime().getMonthValue());
                                // bk1id 存放日期 yyyymmdd ，便于统计
                                consumeenergy.setBk1id(consumeenergy.getYyyymm() * 100 + sensorData.getTime().getDayOfMonth());
                                consumeenergy.setEndtime(sensorData.getTime()); // StartTime待insert
                                // SchedulingConfig.energyQueue.add(consumeenergy);
                                producer.sendEnergy(JSON.toJSONString(consumeenergy));
                            }
                        }
                        latestSensorStatusService.putSensorStatus(sensorStatusMap, sensorData);
                    }

                    /*
                    if (savesensordataxx == 1) { // 队列处理不过来。线网暂时不记录 分表数据
                        equipmentData4CheckMapper.deleteByEquipmentid(equipmentId);
                    }
                    */
                }
                // 新增 sensordataDh，写入数据库即可. eqStatusMap.put("sensorDataDh", sensorDataMap_dhList);
                if (equipmentStatus.getSensorDataDh() != null && !equipmentStatus.getSensorDataDh().isEmpty()) {
                    for (SensorData sensorData : equipmentStatus.getSensorDataDh()) {

                        if (sensorData.getRMS() == null ){
                            log.error("RMS字段不能为 null");

                            respBody.put("errorCode", 1005);
                            respBody.put("errorMsg", "RMS字段不能为 null");
                            return respBody;
                        }

                        sensorData.setUpload_Status(null);

                        if (sensorData.getEq_ID() == null) // 广日可能不传这3个，使用header
                            sensorData.setEq_ID(equipmentStatus.getEq_ID());
                        if (sensorData.getStation_ID() == null)
                            sensorData.setStation_ID(equipmentStatus.getStation_ID());
                        if (sensorData.getTime() == null)
                            sensorData.setTime(equipmentStatus.getTime());

                        if (savesensordataxx == 1) { // 队列处理不过来。线网暂时不记录 分表数据
                            // sensorDataDhMapper.insert(sensorData);
                            // 2024-05-01 改为缓存
                            DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                            dataTypeAndContent.setDataType(SQLDataType.SENSOR_DATA_DH);
                            dataTypeAndContent.setSensorData(sensorData);
                            producer.sendSqlMessage(sensorData.getEq_ID() % queueofsql, producer.QUEUE_SQL, JSON.toJSONString(dataTypeAndContent));
                        }
                    }
                }
                /* equipmentFault 独立处理了
                if (equipmentStatus.getEquipmentFaults() != null && !equipmentStatus.getEquipmentFaults().isEmpty()) {
                    for (Fault fault : equipmentStatus.getEquipmentFaults()) {
                        // saveFault(fault, true, faultInfoMap); // 只有insert ，结构改为和 faultall 一样
                        if (StringUtils.isEmpty(fault.getDia_Rlt())) {
                            continue;
                        }

                        // dataServerId
                        fault.setDataServerId(equipmentStatus.getDataServerId());
                        fault.setLineid(equipmentStatus.getLineid());
                        fault.setStation_ID(equipmentStatus.getStation_ID());
                        fault.setDeptid(equipmentStatus.getDeptid());

                        if (fault.getEq_ID() == null) // 广日可能不传这2个，使用header
                            fault.setEq_ID(equipmentStatus.getEq_ID());
                        if (fault.getTime() == null)
                            fault.setTime(equipmentStatus.getTime());

                        fault.setDataId(0L);
                        fault.setBk1id(0);
                        fault.setBk2id(0L);
                        fault.setBk3id(0L);

                        //新增的 level
                        FaultInfo f1 = PublicVars.getFaultinfo(faultInfoMapper,fault.getDia_Rlt());
                        if (f1 != null){
                            fault.setDialevel(f1.getDia_Level());
                        } else {
                            fault.setDialevel(0);
                        }

                        saveFaultall(fault, true, sampleseconds);
                    }
                }
                */

                // byGK, 缓慢行驶，不删除latestSensorStatus （status=4, 等同0, 但是没有sensordata）
                if (equipmentStatus.getStatus() <= 4 && sensorStatusMap!=null && sensorStatusMap.isEmpty() == false) { // 缓慢， 更新 latest时间为最新时间，以免误判断网
                    for (WithFlag<SensorStatus> sensorStatusWithFlag : sensorStatusMap.values()) {
                        sensorStatusWithFlag.getEntity().setHappenTime(LocalDateTime.now());
                        if (sensorStatusWithFlag.getEntity().getId() > 0)
                            sensorStatusWithFlag.setFlag(WithFlag.FLAG_UPDATE);
                    }
                    latestSensorStatusService.applySensorStatusChange(sensorStatusMap);
                }
//                if (equipmentStatus.getStatus() < 4) {
//                    latestSensorStatusService.applySensorStatusChange(sensorStatusMap);
//                }

                saveEquipmentStatus(equipmentStatus);
                // 合并在一起的话，原来这个操作是 portal2data 完成的，要改在这里完成
                // ? why if (PublicVars.isPortalWithData == 1)
                {
                    // latestEquipmentStatusDao.delete(equipmentStatus.getEq_ID());
                    if (isSlowRun)
                        equipmentStatus.setRemark("4 Slowly");
                    // 2024-05-01 改为缓存
                    //                    if (latestEquipmentStatusDao.update(equipmentStatus) <= 0) {
                    //                        latestEquipmentStatusDao.insert(equipmentStatus);
                    //                    }

                    if (min_dia_level == 999) min_dia_level = 0;
                    equipmentStatus.setBk1id(min_dia_level);
                    equipmentStatus.setIsSync(0);
                    // 涉及到 latestEquipmentStatuses 的都放到 merge 统一处理。否则会有并发冲突。
//                    if ( min_dia_level > 0 ) {
//                        equipmentStatus.setBk2id((long) LatestSensorStatusData.BJFAULT);
//                    } else if (LatestSensorStatusData.latestEquipmentStatuses.containsKey(equipmentStatus.getEq_ID())) {
//                            equipmentStatus.setBk2id(LatestSensorStatusData.latestEquipmentStatuses.get(equipmentStatus.getEq_ID()).getBk2id()); // 这个字段理论上要根据56来确定。如果没有，就设置0
//                    } else {
//                        equipmentStatus.setBk2id((long) LatestSensorStatusData.BJNONE); // 这个字段理论上要根据56来确定。如果没有，就设置0
//                    }

                    DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                    dataTypeAndContent.setDataType(SQLDataType.LATEST_EQUIPMENT_STATUS);
                    dataTypeAndContent.setEquipmentStatus(equipmentStatus);

                    // 后面用到，表示是否改造了 : SHANGHAI : 默认都改造了
//                    if (!LatestSensorStatusData.has56.containsKey(equipmentStatus.getEq_ID())) {
//                        List<Client_Dm_Params> dm_params = clientDmParamsDao.getParamsUpload(equipmentStatus.getEq_ID());
//                        if (dm_params != null && !dm_params.isEmpty()
//                                && dm_params.get(0).getBk4() != null && dm_params.get(0).getBk4().intValue() == 1) {
//                            LatestSensorStatusData.has56.put(equipmentStatus.getEq_ID(), 0); // bk4 == 1: 未改造， has56=0
//                        } else {
//                            LatestSensorStatusData.has56.put(equipmentStatus.getEq_ID(), 1);
//                        }
//                    }
                    LatestSensorStatusData.has56.put(equipmentStatus.getEq_ID(), 1);

                    if (!isMaintainenceStatus.containsKey(equipmentStatus.getEq_ID())) { // 维保忽略
                        producer.sendSqlMessage(equipmentStatus.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));
                    }
                }

                if (!hasFault) {
                    Fault fault = new Fault();
                    fault.setDataServerId(PublicVars.dataServerId);
                    fault.setDataId(0L);
                    fault.setLineid(equipmentStatus.getLineid());
                    fault.setStation_ID(equipmentStatus.getStation_ID());
                    fault.setEq_ID(equipmentStatus.getEq_ID());
                    fault.setDeptid(equipmentStatus.getDeptid());
                    fault.setTime(equipmentStatus.getTime());
                    fault.setDia_Rlt("0000");
                    fault.setDialevel(0);
                    fault.setBk1id(0);
                    fault.setBk2id(0L);
                    fault.setBk3id(0L);
                    fault.setTotalTimes(1);
                    fault.setPeriod(sampleseconds); //PublicVars.sampleseconds

                    fault.setID(fault.getEq_ID()*100L + 1);
//                    if (latestFaultMapper.updateLatestFault(fault) <= 0) {
//                        latestFaultMapper.insertLatestFault(fault);
//                    }
                    // 2024-05-01 改为缓存
                    DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                    dataTypeAndContent.setDataType(SQLDataType.LATEST_FAULT_INSERT_UPDATE);
                    dataTypeAndContent.setFault(fault);
                    producer.sendSqlMessage(fault.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));

                    publishLatestFault(fault);

                    if (lastHasFault.containsKey(fault.getEq_ID()) && lastHasFault.get(fault.getEq_ID()) != hasFault) {
                        // latestFaultMapper.deleteLatestFaultByEqIdAndId(fault.getEq_ID(), fault.getEq_ID() * 100L + 2);
                        // 2024-05-01 改为缓存
                        DataTypeAndContent dataTypeAndContent2 = new DataTypeAndContent();
                        dataTypeAndContent2.setDataType(SQLDataType.LATEST_FAULT_DELETE);
                        dataTypeAndContent2.setLatestFaultDeleteId(new LatestFaultDeleteId(fault.getEq_ID(), fault.getEq_ID() * 100L + 2));
                        producer.sendSqlMessage(equipmentId % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent2));
                    }

                    lastHasFault.put(fault.getEq_ID(), hasFault);

                    publishDeleteLatestFault(equipmentStatus.getDataServerId(), fault.getEq_ID(),fault.getEq_ID() * 100L + 2);
                }
            }

            // 本地OK再上传
            if (PublicVars.isPortalWithData != 1) {
                producer.sendMessage(equipmentId % queueofdata, producer.QUEUE_EQDATA_PORTAL, sendData);
                if (send2iot == 1) {
                    producer.sendMessage(equipmentId % queueofiot, producer.QUEUE_EQDATA_IOT, sendData);
                }
                //producer.sendMessageToTopic(producer.TOPIC_EQDATA, equipmentId, sendData);
            }
            if (sendAllid2queue2 || euqipmentids2queue2Set.contains(equipmentId)) {
                producer.sendMessage2(equipmentId % queue2ofdata, producer.QUEUE_EQDATA_PORTAL, sendData);
            }

            respBody.put("errorCode", 0);
            respBody.put("errorMsg", "");
            respBody.put("ftpAllFiles", buildFtpAllFilesList(equipmentId));
            return respBody;
        } catch (Exception e) {
            e.printStackTrace();

            respBody.put("errorCode", 9999);
            String errorMsg = e.getMessage();
            if (errorMsg == null || errorMsg.isEmpty()) {
                if (e instanceof NullPointerException) {
                    errorMsg = "NullPointerException";

                    StackTraceElement[] stackTrace = e.getStackTrace();
                    if (stackTrace != null && stackTrace.length > 0) {
                        for (int ss = 0; ss < stackTrace.length; ss++) {
                            if ( !StringUtils.isEmpty(stackTrace[ss].getClassName()) && stackTrace[ss].getClassName().indexOf("com.dahua") >= 0) {
                                log.error("异常发生：{} method name : {} , line at: {}", stackTrace[ss].getFileName(), stackTrace[ss].getMethodName(), stackTrace[ss].getLineNumber());
                            }
                        }
                    } else {
                        log.error("e.getStackTrace() returns null");
                    }

                } else {
                    errorMsg = e.toString();
                }
            }
            respBody.put("errorMsg", errorMsg);

            return respBody;
            //throw new RuntimeException(e);
        }
    }

    // 返回 eqId ，应该是一样的，随意一个即可
    private int syncUploadStatus(String json) {
        //log.info(json);
        int equipmentId=0;
        List<Map<String, String>> fileUploadFinishedList = GsonUtils.getGson().fromJson(json, new TypeToken<List<Map<String, String>>>(){}.getType());
        if (fileUploadFinishedList != null) {
            final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
            for (Map<String, String> map : fileUploadFinishedList) {
                //fileUploadFinishedList.forEach(map -> {
                try {
                    int eqId = Integer.parseInt(map.get("Eq_ID"));
                    equipmentId = eqId;
                    LocalDateTime time = LocalDateTime.parse(map.get("Time"), dateTimeFormatter);
                    int sensorId = Integer.parseInt(map.get("Vib_Sensor_No"));

                        // 2024-05-01 改为缓存 sensorDataManager.updateUploadStatus(eqId, sensorId, time);
                    DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                    dataTypeAndContent.setDataType(SQLDataType.UPLOAD_STATUS);
                    UploadStatus uploadStatus = new UploadStatus(eqId, sensorId, time);
                    dataTypeAndContent.setUploadStatus(uploadStatus);
                    producer.sendSqlMessage(eqId % queueofsql, producer.QUEUE_SQL, JSON.toJSONString(dataTypeAndContent));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
        }
        return equipmentId;
    }

    private int reportNoData(String json) {
        //log.info(json);
        int equipmentId=0;
        List<Map<String, String>> fileUploadFinishedList = GsonUtils.getGson().fromJson(json, new TypeToken<List<Map<String, String>>>(){}.getType());
        if (fileUploadFinishedList != null) {
            for (Map<String, String> map : fileUploadFinishedList) { // 应该只有一个
                equipmentId = Integer.parseInt(map.get("Eq_ID"));
                String reporttime = map.get("Time");
                // sensorDataManager.reportNoData(equipmentId, reporttime);
                // 2024-05-01 改为缓存
                DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                dataTypeAndContent.setDataType(SQLDataType.REPORT_NODATA);
                dataTypeAndContent.setReportNoData(new ReportNoData(equipmentId, reporttime));
                producer.sendSqlMessage(equipmentId % queueofsql, producer.QUEUE_SQL, JSON.toJSONString(dataTypeAndContent));
            };
        }
        return equipmentId;
    }

    private List<Integer> buildFtpAllFilesList(int equipmentId) {
        List<Integer> resultList = new ArrayList<>();

        // 改为每隔几秒统一获取
        //List<RuntimeParam> runtimeParamList = runtimeParamMapper.getValidFtpAllFilesParamList(equipmentId);
        String prefix = "ftpAllFiles" + equipmentId;
        List<RuntimeParam> runtimeParamList = PublicVars.runtimeParams.stream().filter(item->item.getName().startsWith(prefix)).collect(Collectors.toList());
        if (runtimeParamList != null && !runtimeParamList.isEmpty()) {
            for (RuntimeParam runtimeParam : runtimeParamList) {
                resultList.add(new Integer(runtimeParam.getValue()));
            }
        }
        return resultList;
    }

    // Hitachi: 统一在 RMS 中也上传了一份
    // GuangRi: 只在 RMS 中上传
    // 原 Temp_Val_1 --> RMS
    private void calculateTemperature(EquipmentStatus equipmentStatus) {
        SensorData leftSensorData = null;
        SensorData rightSensorData = null;
        SensorData environmentSensorData = null;
        for (SensorData sensorData : equipmentStatus.getSensorData()) {
            if (sensorData.getVib_Sensor_No() == null) {
                continue;
            }
            switch (sensorData.getVib_Sensor_No()) {
                case 1201:
                case 2201:
                    leftSensorData = sensorData;
                    leftSensorData.setTemp_Val_1(leftSensorData.getRMS());
                    break;
                case 1202:
                case 2202:
                    rightSensorData = sensorData;
                    rightSensorData.setTemp_Val_1(rightSensorData.getRMS());
                    break;
                case 1203:
                case 2203:
                    environmentSensorData = sensorData;
                    break;
            }
        }
        if (environmentSensorData != null && environmentSensorData.getRMS() != null) {
            double environmentTemp = environmentSensorData.getRMS();
            if (leftSensorData != null && leftSensorData.getRMS() != null) {
                double lefTemp = leftSensorData.getRMS();
                double deltaTemp = lefTemp - environmentTemp;
                leftSensorData.setTemp_Val_2(environmentTemp);
                leftSensorData.setTemp_Val_3(deltaTemp);
            }
            if (rightSensorData != null && rightSensorData.getRMS() != null) {
                double rightTemp = rightSensorData.getRMS();
                double deltaTemp = rightTemp - environmentTemp;
                rightSensorData.setTemp_Val_2(environmentTemp);
                rightSensorData.setTemp_Val_3(deltaTemp);
            }
        }
    }

//    private void putRuntimeParam(RuntimeParam runtimeParam) {
//        if (runtimeParamMapper.updateValue(runtimeParam) == 0) {
//            runtimeParamMapper.insertParam(runtimeParam);
//        }
//    }

    private void saveEquipmentStatus(EquipmentStatus equipmentStatus) {
        sendSlowRunOrStop(equipmentStatus.getEq_ID(), equipmentStatus.getStatus());
        // 4 等同于0，为了方便统计和减少记录数量，如果是4，按 0 写入
        if(equipmentStatus.getStatus() == 4) {
            equipmentStatus.setStatus(0);
        }

        // 2024-05-01 改为缓存
        DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
        dataTypeAndContent.setDataType(SQLDataType.EQUIPMENT_STATUS);
        dataTypeAndContent.setEquipmentStatus(equipmentStatus);
        producer.sendSqlMessage(equipmentStatus.getEq_ID() % queueofsql, producer.QUEUE_SQL, JSON.toJSONString(dataTypeAndContent));
        return;

//        saveEquipmentStatusThisMonth(equipmentStatus);
//
//        EquipmentStatus lastEquipmentStatus = equipmentStatusMapper.getLastEquipmentStatus(equipmentStatus.getEq_ID());
//        if (lastEquipmentStatus != null) {
//            // 4 等同于0，为了方便统计和减少记录数量，如果是4，按 0 写入
//            // 5 和其他一样单独统计，由于5是停机状态，长期停机只传输前几条记录，因此 ： 停机时间不能靠5的合计时间。
//
//            boolean statusEqual = lastEquipmentStatus.getStatus().equals(equipmentStatus.getStatus());
//            if (statusEqual && isSameDate(lastEquipmentStatus.getTime(), equipmentStatus.getTime())) {
//                //int period = (int) Duration.between(lastEquipmentStatus.getTime(), equipmentStatus.getTime()).toMinutes();
//                int period = lastEquipmentStatus.getPeriod() + equipmentStatus.getPeriod(); // PublicVars.sampleseconds; // 改为秒
//                equipmentStatusMapper.updateEndTimeAndPeriodAndTotalTimes(equipmentStatus.getTime(), period, lastEquipmentStatus.getTotalTimes() + 1, lastEquipmentStatus.getID());
//                return;
//            }
//        }
//
//        equipmentStatusMapper.insert(equipmentStatus);
    }

//    private void saveEquipmentStatusThisMonth(EquipmentStatus equipmentStatus) {
//        // 后面非当月的通过后台JOB处理
//        // 4 等同于0，为了方便统计和减少记录数量，如果是4，按 0 写入
//        if(equipmentStatus.getStatus() == 4) {
//            equipmentStatus.setStatus(0);
//        }
//
//        // 线路无需记录。
//        if (PublicVars.isPortalWithData == 0) {
//            return;
//        }
//        equipmentStatus.setYyyymm(equipmentStatus.getTime().getYear()*100 + equipmentStatus.getTime().getMonthValue());
//        equipmentStatus.setYyyymmdd(equipmentStatus.getTime().getYear()*10000 + equipmentStatus.getTime().getMonthValue()*100 + equipmentStatus.getTime().getDayOfMonth());
//
//        if (equipmentStatusThisMonthMapper.updateEndTimeAndPeriodAndTotalTimes(equipmentStatus.getEq_ID(),equipmentStatus.getYyyymm(),equipmentStatus.getStatus(),equipmentStatus.getPeriod()) <= 0)
//            equipmentStatusThisMonthMapper.insert(equipmentStatus);
//
//        // 如果不是当天就不用更新了（例如通讯中断后补发的）
//        if (equipmentStatus.getTime().isAfter(LocalDateTime.of(LocalDate.now(), LocalTime.MIN))) {
//            if (equipmentStatusTodayMapper.updateEndTimeAndPeriodAndTotalTimes(equipmentStatus.getEq_ID(), equipmentStatus.getYyyymmdd(), equipmentStatus.getStatus(), equipmentStatus.getPeriod()) <= 0)
//                equipmentStatusTodayMapper.insert(equipmentStatus);
//        }
//
//        if (equipmentStatusAlldayMapper.updateEndTimeAndPeriodAndTotalTimes(equipmentStatus.getEq_ID(),equipmentStatus.getYyyymmdd(),equipmentStatus.getStatus(),equipmentStatus.getPeriod()) <= 0)
//            equipmentStatusAlldayMapper.insert(equipmentStatus);
//    }
//
    private boolean isSameDate(LocalDateTime d1, LocalDateTime d2) {
        return d1.getYear() == d2.getYear() && d1.getMonthValue() == d2.getMonthValue() && d1.getDayOfMonth() == d2.getDayOfMonth();
    }

    /**
     * 保存fault相关表
     * @param fault
     * @param isEquipmentFault
     * @return  null isEquipmentFault为true或者 fault is null
     *          true fault表插入了新的数据
     *          false fault表仅更新数据
     */
    private Boolean saveFault(Fault fault, boolean isEquipmentFault, int sampleseconds) {

        if (fault==null){
            log.error("fault is null");
            return null;
        }

        if (isEquipmentFault) {
            fault.setEndTime(fault.getTime());
            fault.setPeriod(sampleseconds); // PublicVars.sampleseconds
            fault.setTotalTimes(1);

            saveFaultall(fault, true, sampleseconds);
            return null;
            // 设备类直接插入，后面无需处理。
        }

        LocalDateTime endTime1 = LocalDateTime.of(fault.getTime().getYear(), fault.getTime().getMonth(), fault.getTime().getDayOfMonth(), 0, 0);
        LocalDateTime endTime2 = endTime1.plusDays(1).minusNanos(1);

        Fault lastFault = faultMapper.getLastOne(fault.getEq_ID(), fault.getDia_Rlt(), endTime1, endTime2);

        if (lastFault==null) {
            scoreFault(fault);

            fault.setEndTime(fault.getTime());
            fault.setPeriod(sampleseconds); // PublicVars.sampleseconds
            fault.setTotalTimes(1);

            // bk3id 用与 fault faultall 作为 eqid+dlgrlt+bk3id 关联判断同一个fault
            fault.setBk3id(System.currentTimeMillis());
            fault.setBk1id(0);
            fault.setBk2id(0L);

            fault.setIsFixed(0);
            fault.setIsChecked(0);
            fault.setIsReceived(0);

            LocalDateTime time2 = fault.getEndTime();
            fault.setTimeHour(LocalDateTime.of(time2.getYear(), time2.getMonth(), time2.getDayOfMonth(), time2.getHour(), 0));
            fault.setTimeDay(LocalDateTime.of(time2.getYear(), time2.getMonth(), time2.getDayOfMonth(), 0, 0));
            fault.setTimeMonth(LocalDateTime.of(time2.getYear(), time2.getMonth(), 1, 0, 0));
            fault.setTimeYear(time2.getYear());

            //已经配置返回 id
//            faultMapper.insert(fault);
//
//            fault.setBk3id(fault.getID());
//            faultMapper.updateBk3id(fault.getBk3id(),fault.getID());
//
//            publishFault(fault);
//
//            saveFaultall(fault,false, sampleseconds);
//            createWorkbillIfNeed(fault);
            // 2024-05-01 改为缓存
            DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
            dataTypeAndContent.setDataType(SQLDataType.SAVE_FAULT_SYNC);
            dataTypeAndContent.setSaveFaultData(new SaveFaultData(fault, isEquipmentFault, sampleseconds));
            producer.sendSqlMessage(fault.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));

            return true;
        }

        // 2019-12-01 修改规则：
        /*
            1.1、    1-2级别，连续超过14天没有出现 。温度还是原来连续30分钟。（两个参数都是配置） 才算下一次。
            1.2、    3级 ：只有修复才算下一次
            1.3、    3级 :  每次新的请求，自动插入一条 急修工单  --> portal端口实现
    类似这个方式可以拿到期间内最早和最新的报警时间
         select eq_id, dia_rlt, min(Time), max(Time) from fault where ... group by eq_id, dia_rlt, remark
         */
        // 老规则使用 Time, 新规则使用 EndTime
        // 第一次插入，已经设置 EndTime 了
        // 无需判断是否新的一天

        FaultInfo theFaultInfo = PublicVars.getFaultinfo(faultInfoMapper,fault.getDia_Rlt());
        int levelDH = 1;
        if (theFaultInfo != null) {
            levelDH = theFaultInfo.getDia_Level_DH(); // 根据大华LEVEL判断
        }
        // DH三级，只有处理完毕才计算下一次
        LocalDateTime lastFaultTime = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
        if (levelDH == 3 && lastFault.getIsFixed() == 1){ // 已经改进，查询条件增加了isFixed=0,这步没用到了
            ; // DH三级，一旦处理完毕，再次出现即为下一次。
        } else {
            lastFaultTime = lastFault.getEndTime();  // 使用 EndTime，上次时间
        }
        /*
        if (lastFault != null) {
            if (!lastFault.getIsFixed()) {
                if (isSameDate(lastFault.getTime(), fault.getTime())) {
                    lastFaultTime = lastFault.getTime();
                }
            }
        }
        */
        int minutesDiff = (int) Duration.between(lastFaultTime, fault.getTime()).toMinutes();
        // 由于上面 lastFaultTime 已经采用 lastEndTime,因此,这里的判断就是 XX 时间没有出现了。
        boolean isNew=isInsertFault(fault, minutesDiff);
        boolean isAnotherDay=!isSameDate(lastFault.getTime(), fault.getTime());
        //if (isNew || isAnotherDay) {
        if (isNew) {
            scoreFault(fault);
            fault.setEndTime(fault.getTime());
            fault.setPeriod(sampleseconds); // PublicVars.sampleseconds
            fault.setTotalTimes(1);

            // bk3id 用与 fault faultall 作为 eqid+dlgrlt+bk3id 关联判断同一个fault
            if (isNew) {
                fault.setBk3id(System.currentTimeMillis());
            } else {
                fault.setBk3id(lastFault.getBk3id());
            }

            fault.setBk1id(0);
            fault.setBk2id(0L);

            fault.setIsFixed(0);
            fault.setIsChecked(0);
            fault.setIsReceived(0);

            LocalDateTime time2 = fault.getEndTime();
            fault.setTimeHour(LocalDateTime.of(time2.getYear(), time2.getMonth(), time2.getDayOfMonth(), time2.getHour(), 0));
            fault.setTimeDay(LocalDateTime.of(time2.getYear(), time2.getMonth(), time2.getDayOfMonth(), 0, 0));
            fault.setTimeMonth(LocalDateTime.of(time2.getYear(), time2.getMonth(), 1, 0, 0));
            fault.setTimeYear(time2.getYear());

            //已经配置返回 id
//            faultMapper.insert(fault);
//
//            fault.setBk3id(fault.getID());
//            faultMapper.updateBk3id(fault.getBk3id(),fault.getID());
//
//            publishFault(fault);
//
//            saveFaultall(fault,false, sampleseconds);
//            createWorkbillIfNeed(fault);
            // 2024-05-01 改为缓存
            DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
            dataTypeAndContent.setDataType(SQLDataType.SAVE_FAULT_SYNC);
            dataTypeAndContent.setSaveFaultData(new SaveFaultData(fault, isEquipmentFault, sampleseconds));
            producer.sendSqlMessage(fault.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));

            // 不管是否new,都执行 createWorkbillIfNeed(fault);
        } else {
            // 不能用 上面的minutesDiff，可以断断续续了。
            // 因此改为 上次时间 + 20秒。 可以配置。折算为分钟
//            int period = lastFault.getPeriod() + sampleseconds; //PublicVars.sampleseconds;
//
//            faultMapper.updateEndTimeAndPeriodAndTotalTimes(fault.getTime(), period, lastFault.getTotalTimes() + 1, lastFault.getID());
//
//            //@Update("update fault set EndTime=#{endTime, jdbcType = TIMESTAMP}, Period=#{period}, TotalTimes=#{totalTimes} where ID=#{id}")
//            lastFault.setEndTime(fault.getTime());
//            lastFault.setTotalTimes(lastFault.getTotalTimes() + 1);
//            lastFault.setPeriod(period);
//
//            publishFault(lastFault);
//
//            fault.setID(lastFault.getID());
//            fault.setBk1id(lastFault.getBk1id());
//            fault.setBk2id(lastFault.getBk2id());
//            fault.setBk3id(lastFault.getBk3id());
//            fault.setIsFixed(lastFault.getIsFixed());
//
//            // 这个注意使用 lastFault,但是时间设置为 当前fault
//            // 因为很多属性只有 lastFault 才有
//            Fault newFault= lastFault;
//            newFault.setTime(fault.getTime());
//            newFault.setEquipmentbrandid(fault.getEquipmentbrandid());
//            newFault.setPartbrandid(fault.getPartbrandid());
//            newFault.setPartgroupid(fault.getPartgroupid());
//            newFault.setPartid(fault.getPartid());
//            newFault.setSupplierid(fault.getSupplierid());
//            newFault.setSensorid(fault.getSensorid());
//            newFault.setSensortype(fault.getSensortype());
//            newFault.setBk1(fault.getBk1());
//            saveFaultall(newFault, false, sampleseconds);
//            createWorkbillIfNeed(fault);
            // 2024-05-01 改为缓存
            DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
            dataTypeAndContent.setDataType(SQLDataType.SAVE_FAULT_UPDATE_SYNC);
            dataTypeAndContent.setSaveFaultData(new SaveFaultData(fault, isEquipmentFault, sampleseconds, lastFault));
            producer.sendSqlMessage(fault.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));

        }
        return isNew;
    }

    /**
     * 如果是线网级consumer，故障评分并填充Fault remark:评分部件规则的部件分类  dataId:评分 字段
     * @param fault
     */
    private void scoreFault(Fault fault) {
        if (PublicVars.isPortalWithData != 1) {
            return;
        }
        if (fault.getPartgroupid() != null) {
            Partgroup partgroup = PublicVars.getPartgroup(partgroupDao, fault.getPartgroupid());
            if (partgroup != null && !StringUtils.isEmpty(partgroup.getBk1())) {
                fault.setRemark(partgroup.getBk1());
                long score = PublicVars.calcPartScore(dictDetailMapper, fault.getRemark(), fault.getSensortype(),
                        fault.getDialevel(), fault.getBk1());
                if (score > 0) {
                    log.error("出现异常扣分值: " + score);
                    score = 0;
                }
                fault.setDataId(score);
                return;
            }
        }
        fault.setRemark(null);
        fault.setDataId(0L);
    }

    private boolean isCreateWorkbill(Fault fault) {
        // getDialevel 地铁 fault.setDialevel(f1.getDia_Level());
        // return 1 == fault.getDialevel() && !Optional.ofNullable(workbillDao.existsWorkbill(fault.getEq_ID(), fault.getDia_Rlt(), fault.getBk3id())).orElse(false);
        // bk2id 记录 workbillid : 未创建workbill 或者 已经修复
        return 1 == create_workbill && 1 == fault.getDialevel()
                && (fault.getBk2id() == 0L || fault.getBk2id() == null || fault.getIsFixed() == 1);
    }

    private void createWorkbillIfNeed(Fault fault) {
        if (PublicVars.isPortalWithData == 1 && isCreateWorkbill(fault)) {
            try {
                SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
                requestFactory.setConnectTimeout(30000); //设置超时
                requestFactory.setReadTimeout(60000);
                RestTemplate restTemplate = new RestTemplate(requestFactory);
                //RestTemplate restTemplate = new RestTemplate();
                String url = PublicVars.centralPortalApiBaseUrl + "/workbill/fromFault/" + fault.getID();
                log.info(url);
                ResponseEntity<Long> resp = restTemplate.postForEntity(url, null, Long.class);
                if (resp.getStatusCode().isError()) {
                    // throw new RuntimeException(resp.getStatusCode().value() + " " + resp.getStatusCode().getReasonPhrase());
                    log.error("url = {} ", url);
                    log.error("getStatusCode = {} ", resp.getStatusCode().value());
                    log.error("getReasonPhrase = {} ", resp.getStatusCode().getReasonPhrase());
                } else {
                    // 工单号
                    if (resp.getBody() != null && resp.getBody() > 0)
                        fault.setBk2id(resp.getBody());
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }


    //2019-12-01 : minutesDiff 使用 lastEndTime比较，因此已经是等于上次出现之后
    private boolean isInsertFault(Fault fault, int minutesDiff) {
        if ((fault.getDia_Rlt().startsWith("LH") || fault.getDia_Rlt().startsWith("RH")) && minutesDiff > PublicVars.intervalTemperature) {
            return true;
        }
        FaultInfo faultInfo = PublicVars.getFaultinfo(faultInfoMapper,fault.getDia_Rlt());
        if (faultInfo != null) {
            switch (faultInfo.getDia_Level_DH()) {
                case 1:
                case 2:
                    return minutesDiff > PublicVars.intervalDH12;
                case 3:
                    return  minutesDiff > PublicVars.intervalDH3;
            }
        }
        return false;
    }

    @GetMapping("/test")
    public String test() {
        //return "success" + LocalDateTime.now().toString();
        return diskUsageInfo;
    }
    @GetMapping("/mqtest")
    public String mqtest() {
        return String.format("status:%d-%d-%d, sensor:%d-%d, control56:%d-%d-%d, elevator:%d-%d-%d, upload:%d-%d-%d, eqf: %d-%d-%d, eqf-dh: %d-%d-%d , %s, running2StopEquipmentStatus=%d",
                QueueTimes.countData, QueueTimes.mqData, QueueTimes.tryData,
                QueueTimes.mqSensorData, QueueTimes.trySensorData,
                QueueTimes.count56, QueueTimes.mq56, QueueTimes.try56,
                QueueTimes.count56z, QueueTimes.mq56z, QueueTimes.try56z,
                QueueTimes.countUpload, QueueTimes.mqUpload, QueueTimes.tryUpload,
                QueueTimes.countEquipmentFault, QueueTimes.mqEquipmentFault,  QueueTimes.tryEquipmentFault,
                QueueTimes.countEquipmentFault_dh, QueueTimes.mqEquipmentFault_dh,  QueueTimes.tryEquipmentFault_dh, Latest56AndEqf2Web.getConsumerCountInfo(), PublicVarsTimeDay.running2StopEquipmentStatus.size());
    }
    @GetMapping("/wstime")
    public String wstime() {
        //return "success" + LocalDateTime.now().toString();
        return wsTime.toString() + " , total:" + LatestSensorStatusData.latestSensorStatusData.size();
    }
    @GetMapping("/message/{eqId}")
    public String message(@PathVariable("eqId") Integer eqId) {
        if (equipmentMessage.containsKey(eqId))
            return  equipmentMessage.get(eqId);
        else
            return "no message : " + LocalDateTime.now().toString();
    }
    @GetMapping("/message2/{eqId}")
    public String message2(@PathVariable("eqId") Integer eqId) {
        if (equipmentMessageAll.containsKey(eqId))
            return  equipmentMessageAll.get(eqId);
        else
            return "no message2 : " + LocalDateTime.now().toString();
    }
    @GetMapping("/message3/{eqId}")
    public String message3(@PathVariable("eqId") Integer eqId) {
        if (wrongFileInfo.containsKey(eqId))
            return  wrongFileInfo.get(eqId);
        else
            return "no wrongFileInfo : " + LocalDateTime.now().toString();
    }
    @GetMapping("/message3/all")
    public String message3() {
        if (wrongFileInfo.isEmpty())
            return "no wrongFileInfo : ";
        else
            return new Gson().toJson(wrongFileInfo);
    }
    // 查看工控机数据原始数据和检查文件情况
    @GetMapping("/client/{eqId}/{statusTime}")
    public String message3(@PathVariable("eqId") Integer eqId, @PathVariable("statusTime") String statusTime) {
        // yyyy-MM-dd HH:mm:ss 格式
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = sdf.parse(statusTime);
            statusTimeRequest.put(eqId, statusTime);
        } catch (Exception e) {
            return "日期格式错误";
        }
        return "OK";
    }
    @GetMapping("/message4/all")
    public String message4() {
        if (statusTimeResult.isEmpty())
            return "no statusTimeResult : ";
        else
            return new Gson().toJson(statusTimeResult);
    }
    @GetMapping("/message5/{eqId}")
    public String message5(@PathVariable("eqId") Integer eqId) {
        if (statusTimeResult.containsKey(eqId) == false)
            return "no statusTimeResult : ";
        else
            return  statusTimeResult.get(eqId);
    }

    // 0:all,  4, :通讯失败,  8:通讯OK
    @GetMapping("/server/{eqId}")
    public String server(@PathVariable("eqId") Integer eqId) {
        if (db2serverInfo.isEmpty())
            return "no db2serverInfo(empty)";

        if (eqId == 0)
            return new Gson().toJson(db2serverInfo);

        if (eqId == 4) {
            Map<Integer, String> failed = new HashMap<>();
            db2serverInfo.forEach( (k, v) -> {
                if (v.contains("通讯失败"))
                    failed.put(k, v);
            });
            return new Gson().toJson(failed);
        }

        if (eqId == 8) {
            Map<Integer, String> ok = new HashMap<>();
            db2serverInfo.forEach( (k, v) -> {
                if (v.contains("通讯OK"))
                    ok.put(k, v);
            });
            return new Gson().toJson(ok);
        }

        if (db2serverInfo.containsKey(eqId) == false)
            return "no db2serverInfo of : " + eqId;
        else
            return  db2serverInfo.get(eqId);
    }

    //因为没有提供设置手段，暂时插入数据库后调用这个URL，直接读取config。
    @GetMapping("/readconfig")
    public String readconfig() {
        PublicVars.hasApplicationInit=false;
        return "success , set hasApplicationInit=false OK " + LocalDateTime.now().toString();
    }

    /**
     * 字符串的解压
     *
     * @param str
     *            对字符串解压
     * @return    返回解压缩后的字符串
     * @throws IOException
     */
    public String unCompress_old(String str) throws IOException {
        if (null == str || str.length() <= 0) {
            return str;
        }
        // 创建一个新的 byte 数组输出流
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // 创建一个 ByteArrayInputStream，使用 buf 作为其缓冲区数组
        ByteArrayInputStream in = new ByteArrayInputStream(str
                .getBytes("ISO-8859-1"));
        // 使用默认缓冲区大小创建新的输入流
        GZIPInputStream gzip = new GZIPInputStream(in);
        byte[] buffer = new byte[4096];
        int n = 0;
        while ((n = gzip.read(buffer)) >= 0) {// 将未压缩数据读入字节数组
            // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte数组输出流
            out.write(buffer, 0, n);
        }
        // 使用指定的 charsetName，通过解码字节将缓冲区内容转换为字符串
        return out.toString("ISO-8859-1");
        //return out.toString();
    }
    public String unCompress(byte[] compressedBytes) throws IOException {
        if (null == compressedBytes || compressedBytes.length == 0) {
            return "";
        }
        InputStream inStream = new GZIPInputStream(
                new ByteArrayInputStream(compressedBytes));
        ByteArrayOutputStream baoStream2 = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int len;
        while ((len = inStream.read(buffer)) > 0) {
            baoStream2.write(buffer, 0, len);
        }
        return baoStream2.toString("UTF-8");
    }

    private void saveFaultall(Fault fault, Boolean isEquipmentFault, int sampleseconds) {
        Faultall faultall = copyFromFault(fault,isEquipmentFault, sampleseconds);

        if (!isEquipmentFault) {
            // 2020-10-02 改为按天记录. Time -- EndTime
            List<Faultall> faultalls = faultallMapper.selectByEqidDiarltTimeday(faultall);
            if (faultalls == null || faultalls.isEmpty()) {

                // faultallMapper.insert(faultall);
                // 2024-05-01 改为缓存
                DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                dataTypeAndContent.setDataType(SQLDataType.FAULT_ALL_INSERT);
                dataTypeAndContent.setFaultall(faultall);
                producer.sendSqlMessage(faultall.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));

                publishFaultall(faultall);
            } else {
                Faultall lastfaultall = faultalls.get(0);
                lastfaultall.setTotalTimes(lastfaultall.getTotalTimes() + 1);
                lastfaultall.setPeriod(lastfaultall.getPeriod() + sampleseconds);
                lastfaultall.setEndTime(fault.getEndTime());

                //faultallMapper.updateByIdSync(lastfaultall);
                // 2024-05-01 改为缓存
                DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                dataTypeAndContent.setDataType(SQLDataType.FAULT_ALL_UPDATE);
                dataTypeAndContent.setFaultall(lastfaultall);
                producer.sendSqlMessage(lastfaultall.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));

                publishFaultall(lastfaultall);
            }
        } else {
            // 修改： 每天只记录一条
            // 2020-12-16 改为按天记录. Time -- EndTime same as above
//            int ret = equipmentFaultMapper.update(faultall);
//            if (ret == 0) {
//                equipmentFaultMapper.insert(faultall);
//            }
            // 2024-05-01 改为缓存
            DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
            dataTypeAndContent.setDataType(SQLDataType.EQUIPMENT_FAULT);
            dataTypeAndContent.setFaultall(faultall);
            producer.sendSqlMessage(faultall.getEq_ID() % queueofsqleqf, producer.EQUIPMENTFAULT_SQL, JSON.toJSONString(dataTypeAndContent));
        }
    }

    private void saveEquipmentFault_dh(Fault fault, int sampleseconds) {
        Faultall faultall = copyFromFault(fault,true, sampleseconds);
        // 上述默认totalTimes = 1 , 新版次数ID中。旧版 ID == null,不变
        if (fault.getID() != null && fault.getID() > 1L && fault.getID() < 8888L) {
            faultall.setTotalTimes(Integer.parseInt(fault.getID().toString()));
            faultall.setPeriod(faultall.getTotalTimes() * faultall.getPeriod());
        }

        // 修改： 每天只记录一条
        // 2020-12-16 改为按天记录. Time -- EndTime same as above
        // 理论上原来ID为NULL，修改为次数了。遇到为NULL的是老版本，设置为1

//        int ret = equipmentFaultDhMapper.update(faultall);
//        if (ret == 0) {
//            equipmentFaultDhMapper.insert(faultall);
//        }
        // 2024-05-01 改为缓存
        DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
        dataTypeAndContent.setDataType(SQLDataType.EQUIPMENT_FAULT_DH);
        dataTypeAndContent.setFaultall(faultall);
        producer.sendSqlMessage(faultall.getEq_ID() % queueofsqleqf, producer.EQUIPMENTFAULT_SQL, JSON.toJSONString(dataTypeAndContent));

    }

    private Faultall copyFromFault(Fault fault, Boolean isEquipmentFault, int sampleseconds) {
        Faultall faultall = new Faultall();
        faultall.setDataServerId(fault.getDataServerId());
        faultall.setDataId(fault.getDataId());
        faultall.setStation_ID(fault.getStation_ID());
        faultall.setEq_ID(fault.getEq_ID());
        faultall.setDeptid(fault.getDeptid());
        faultall.setBk3id(fault.getBk3id());
        faultall.setDia_Rlt(fault.getDia_Rlt());
        faultall.setDialevel(fault.getDialevel());
        faultall.setLineid(fault.getLineid());
        faultall.setTime(fault.getTime());
        faultall.setTotalTimes(1);
        faultall.setPeriod(sampleseconds); //PublicVars.sampleseconds
        faultall.setEndTime(fault.getTime());
        faultall.setRemark(fault.getRemark());

        // 新增7大id
        if (!isEquipmentFault) {
            faultall.setEquipmentbrandid(fault.getEquipmentbrandid());
            faultall.setPartbrandid(fault.getPartbrandid());
            faultall.setPartgroupid(fault.getPartgroupid());
            faultall.setPartid(fault.getPartid());
            faultall.setSupplierid(fault.getSupplierid());
            faultall.setSensorid(fault.getSensorid());
            faultall.setSensortype(fault.getSensortype());

            faultall.setBk1(fault.getBk1());
            faultall.setBk2(fault.getBk2());
            faultall.setBk3(fault.getBk3());
            faultall.setBk4(fault.getBk4());
            faultall.setBk5(fault.getBk5());
        }

        LocalDateTime time = fault.getTime();
        faultall.setTimeHour(LocalDateTime.of(time.getYear(), time.getMonth(), time.getDayOfMonth(), time.getHour(), 0));
        faultall.setTimeDay(LocalDateTime.of(time.getYear(), time.getMonth(), time.getDayOfMonth(), 0, 0));
        faultall.setTimeMonth(LocalDateTime.of(time.getYear(), time.getMonth(), 1, 0, 0));

        return faultall;
    }
    private Faultall copyFromFault4Control56(Fault fault) {
        Faultall faultall = new Faultall();
        faultall.setDataServerId(fault.getDataServerId());
        faultall.setDataId(fault.getDataId());
        faultall.setStation_ID(fault.getStation_ID());
        faultall.setEq_ID(fault.getEq_ID());
        faultall.setDeptid(fault.getDeptid());
        faultall.setBk3id(fault.getBk3id());
        faultall.setDia_Rlt(fault.getDia_Rlt());
        faultall.setDialevel(fault.getDialevel());
        faultall.setLineid(fault.getLineid());
        faultall.setTime(fault.getTime());
        faultall.setTotalTimes(1);
        faultall.setPeriod(PublicVars.sampleseconds);
        faultall.setEndTime(fault.getTime());

        // 新增7大id
        faultall.setEquipmentbrandid(fault.getEquipmentbrandid());
        faultall.setPartbrandid(fault.getPartbrandid());
        faultall.setPartgroupid(fault.getPartgroupid());
        faultall.setPartid(fault.getPartid());
        faultall.setSupplierid(fault.getSupplierid());
        faultall.setSensorid(fault.getSensorid());
        faultall.setSensortype(fault.getSensortype());

        faultall.setBk1(fault.getBk1());
        faultall.setBk2(fault.getBk2());
        faultall.setBk3(fault.getBk3());
        faultall.setBk4(fault.getBk4());
        faultall.setBk5(fault.getBk5());


        LocalDateTime time = fault.getTime();
        faultall.setTimeHour(LocalDateTime.of(time.getYear(), time.getMonth(), time.getDayOfMonth(), time.getHour(), 0));
        faultall.setTimeDay(LocalDateTime.of(time.getYear(), time.getMonth(), time.getDayOfMonth(), 0, 0));
        faultall.setTimeMonth(LocalDateTime.of(time.getYear(), time.getMonth(), 1, 0, 0));

        return faultall;
    }

    /* 2023-05-02: statuscode : Z- 开头是直梯
        statuscode 字段 varchar(10) : 用 Z- 开头表示这个是直梯的信息，例如 Z-1
        faultcode 字段 varchar(10) : 格式：故障码-楼层码 从目前日立数据分析，故障码和楼层码都是 16bit，也就是 2bytes。 中间用 - 隔开。
            例如 3-1 表示：开关门锁死故障， 停在 1楼
       -- insert into dict(id, name, remark) values(80, 'elevator_status','电梯状态位');
       字典配置不同品牌
     */
    @PostMapping("/control56")
    //public Map syncData(@RequestBody String base64Str) {
    public Map control56(@RequestBody byte[] sendData, HttpServletRequest request) {
        boolean isElevator = false;
        Map respBody = new HashMap();
        if (!checkInitialOK(respBody)) {
            return respBody;
        }

        try {
            // 用于打印通讯时间和解密前后内容
            printInfo(sendData);

            String mapStr = unCompress(sendData);
            if (PublicVars.printCommunicationInfo == 1 || PublicVars.printEncryptionData == 1) {
                log.info("解密解压后长度：" + mapStr.length());
                log.info("解密解压后内容：" + mapStr);
            }

            Map<String, String> jsonMap = GsonUtils.getGson().fromJson(mapStr, new TypeToken<Map<String, String>>() {
            }.getType());

            String eqDataJson = jsonMap.get("control56Data");
            if (eqDataJson == null) {
                log.error("数据不合法，没有找到 control56Data 节点数据 ");

                respBody.put("errorCode", 1020);
                respBody.put("errorMsg", "缺少 control56Data 节点数据 ");
                return respBody;
            }
            List<Control56> control56List = GsonUtils.getGson().fromJson(eqDataJson, new TypeToken<List<Control56>>() {
            }.getType());

            //缓存Map<String, FaultInfo> faultInfoMap = faultInfoMapper.getAllFaultInfoMap();
            for (Control56 control56 : control56List) {
                if (control56.getEquipmentid() == null || control56.getEquipmentid() <= 0) {
                    log.error("缺少 设备id ");

                    respBody.put("errorCode", 1010);
                    respBody.put("errorMsg", "缺少 设备id ");
                    return respBody;
                }

                Equipment e1 = PublicVars.getEquipment(equipmentMapper,control56.getEquipmentid());
                if (e1!=null){
                    control56.setDeptid(e1.getDeptid());
                    control56.setLineid(e1.getLineid());
                    control56.setStationid(e1.getStationId());
                    control56.setBk2(e1.getBk2()); // 设备类型
                    control56.setBk5(e1.getBk5()); // 设备分级
                } else {
                    log.error(String.format("服务器端尚未配置该设备id: %d , ip: %s ", control56.getEquipmentid(), request.getRemoteAddr()));

                    respBody.put("errorCode", 1000);
                    respBody.put("errorMsg", "服务器端尚未配置该设备id : " + control56.getEquipmentid());
                    return respBody;
                    // throw new RuntimeException("服务器端尚未配置该设备编码");
                }


                if ("ZT".equals(e1.getBk2())) {
                    ElevatorControl56(control56, respBody, e1);
                } else if ("FT".equalsIgnoreCase(e1.getBk2()) || "FT2".equalsIgnoreCase(e1.getBk2())) {
                    FTControl56(control56, respBody, e1);

                    PublicVarsTimeDay.setRunningStopingBy56(control56, true);
                } else {
                    log.error("不支持的设备类型(FT ZT)，该设备id : " + control56.getEquipmentid());

                    respBody.put("errorCode", 1030);
                    respBody.put("errorMsg", "不支持的设备类型(FT ZT)，该设备id : " + control56.getEquipmentid());
                }
                if (!respBody.isEmpty()) {
                    return respBody;
                }
            }

            // 本地OK再上传
            if (PublicVars.isPortalWithData != 1) {
                producer.sendMessage(control56List.get(0).getEquipmentid() % queueof56, producer.QUEUE_CONTROL56_PORTAL, sendData);
                if (send2iot == 1) {
                    producer.sendMessage(control56List.get(0).getEquipmentid() % queueof56, producer.QUEUE_CONTROL56_IOT, sendData);
                }
                //producer.sendMessageToTopic(producer.TOPIC_CONTROL56, equipmentId, sendData);
            }
            if ( queue2of56 > 0
                    && (sendAllid2queue2 || euqipmentids2queue2Set.contains(control56List.get(0).getEquipmentid()))
                    && (sendElevator2queue2 == 1 || !isElevator)
            ) {
                producer.sendMessage2(control56List.get(0).getEquipmentid() % queue2of56, producer.QUEUE_CONTROL56_PORTAL, sendData);
            }

            respBody.put("errorCode", 0);
            respBody.put("errorMsg", "");

            return respBody;
        } catch (Exception e) {
            e.printStackTrace();

            respBody.put("errorCode", 9999);
            String errorMsg = e.getMessage();
            if (errorMsg == null || errorMsg.isEmpty()) {
                if (e instanceof NullPointerException) {
                    errorMsg = "NullPointerException";

                    StackTraceElement[] stackTrace = e.getStackTrace();
                    if (stackTrace != null && stackTrace.length > 0) {
                        for (int ss = 0; ss < stackTrace.length; ss++) {
                            if ( !StringUtils.isEmpty(stackTrace[ss].getClassName()) && stackTrace[ss].getClassName().indexOf("com.dahua") >= 0) {
                                log.error("异常发生：{} method name : {} , line at: {}", stackTrace[ss].getFileName(), stackTrace[ss].getMethodName(), stackTrace[ss].getLineNumber());
                            }
                        }
                    } else {
                        log.error("e.getStackTrace() returns null");
                    }

                } else {
                    errorMsg = e.toString();
                }
            }
            respBody.put("errorMsg", errorMsg);

            return respBody;
            // throw new RuntimeException(e);
        }
    }
    // 可能一个动作短时间重复（状态码编码，故障码不变）
    private boolean isControl56FaultRepeat(Integer equipmentId, String faultCode) {
        // return false;
        // 不再判断，有时候维保就是要来回触发 --> 还是判断，因为这个只影响fault，不影响control56
        String key = equipmentId.toString() + "----" +faultCode;
        LocalDateTime lastTime = StaticData.lastControl56.get(key);
        StaticData.lastControl56.put(key,LocalDateTime.now()); // 均最新为准
        if (lastTime == null) {
            return false;
        }
        if (Duration.between(lastTime,LocalDateTime.now()).toMinutes() > PublicVars.control56FaultMinutes){
            return false;
        }
        return true;
    }

    private void saveControl56(Control56 control56, String type) {

        LatestSensorStatusData.latest56.put(control56.getEquipmentid(), control56);
        LatestSensorStatusData.hasLatest56.put(control56.getEquipmentid(), 1);

        boolean sameAsLast = false;
        if (lastControl56s.containsKey(control56.getEquipmentid())) {
            Control56 lastControl56 =  lastControl56s.get(control56.getEquipmentid());
            if (lastControl56.getStatuscode().equals(control56.getStatuscode())
                    && lastControl56.getFaultcode().equals(control56.getFaultcode())) {
                sameAsLast = true;
            }
        }
        if (!sameAsLast) {
            //control56Mapper.insert(control56);
            lastControl56s.put(control56.getEquipmentid(), control56);
            // 2024-05-01 改为缓存
            QueueTimes.count56P1();
            DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
            dataTypeAndContent.setDataType(SQLDataType.CONTROL56);
            dataTypeAndContent.setControl56(control56);
            producer.sendSqlMessage(control56.getEquipmentid() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));
        }

        if (web56 == 1) {
            Control56SmallDTO control56SmallDTO = PublicVars.buildControl56Small(control56, control56configMappper);
            if (control56SmallDTO != null) {
                Latest56AndEqf2Web.saveControl56(control56SmallDTO);
                /*
                SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
                requestFactory.setConnectTimeout(30000); //设置超时
                requestFactory.setReadTimeout(60000);
                RestTemplate restTemplate = new RestTemplate(requestFactory);
                //RestTemplate restTemplate = new RestTemplate();
                String url = PublicVars.serverBaseUrl + "/control56InMemory";
                try {
                    restTemplate.put(url, control56SmallDTO);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // System.out.println(url);
                 */
            }
        }
    }
    /**
     * 保存fault相关表
     * @param control56
     * @param f1
     * @param e1
     */
    private void saveFault4Control56(Control56 control56, FaultInfo f1, Equipment e1, String faultCode, boolean onlyUpdateLatestEquipmentStatus) {
        if (control56==null || f1==null){
            log.error("fault is null || faultInfo==null");
            return ;
        }
        // 维保期间，不记录故障
        if (isMaintainenceStatus.containsKey(control56.getEquipmentid()))
            return;


        Fault fault = new Fault();
        fault.setDataServerId(control56.getDataserverid());
        fault.setDataId(control56.getDataid());
        fault.setStation_ID(control56.getStationid());
        fault.setEq_ID(control56.getEquipmentid());
        fault.setDeptid(control56.getDeptid());
        fault.setDia_Rlt(faultCode);
        fault.setDialevel(f1.getDia_Level());
        fault.setLineid(control56.getLineid());
        fault.setTime(control56.getTime());
        fault.setTotalTimes(1);
        fault.setPeriod(PublicVars.sampleseconds);
        fault.setEndTime(control56.getTime());

        fault.setBk3id(System.currentTimeMillis());
        fault.setBk1id(0);
        fault.setBk2id(0L);

        fault.setBk2(e1.getBk2()); // 设备类型
        fault.setBk5(e1.getBk5()); // 设备分级

        fault.setSensortype(f1.getRemark());
        fault.setBk1(f1.getFaultclass()); // 故障分类
        fault.setBk4(control56.getBk4()); // 故障类型：扶梯设备、扶梯安全开关、直梯设备

        //新增加的几个字段：品牌、分类等
        fault.setEquipmentbrandid(e1.getBrandid());
        // 是否有合法的传感器id
        if (f1!=null){
            Sensor sensor = PublicVars.getSensorinfo(sensorMapper,f1.getPartcode());
            if (sensor != null){
                fault.setSensorid(sensor.getID());
                // No rms
                // fault.setSensortype(sensor.getSensor_type());
                fault.setPartgroupid(sensor.getPartgroupid());
                // 继续找设备部件+部件
                Equipmentparts equipmentparts =PublicVars.getEquipmentpartsInfo(equipmentpartsMapper,fault.getEq_ID(),fault.getSensorid());
                if (equipmentparts!=null){
                    fault.setPartid(equipmentparts.getPartid());
                    Part part = PublicVars.getPartinfo(partMapper,equipmentparts.getPartid());
                    if (part !=null){
                        fault.setPartbrandid(part.getBrandid());
                        fault.setSupplierid(part.getSupplierid());
                    }
                }
            }
        }

        if (!onlyUpdateLatestEquipmentStatus) {
            scoreFault(fault);
//            //已经配置返回 id
//            faultMapper.insert(fault);
//            fault.setBk3id(fault.getID());
//            faultMapper.updateBk3id(fault.getBk3id(), fault.getID());
//
//            fault.setIsFixed(0);
//            fault.setIsChecked(0);
//            fault.setIsReceived(0);
//            publishFault(fault);
//
//            // latestfault
//            //latestFaultMapper.deleteLatestFaultByStationIdAndEqId(fault.getStation_ID(), fault.getEq_ID());
//            fault.setID(fault.getEq_ID() * 100L + 1);
//            if (latestFaultMapper.updateLatestFault(fault) <= 0) {
//                latestFaultMapper.insertLatestFault(fault);
//            }
//            publishLatestFault(fault);
//            latestFaultMapper.deleteLatestFaultByEqIdAndId(fault.getEq_ID(), fault.getEq_ID() * 100L + 2);
//            publishDeleteLatestFault(fault.getDataServerId(), fault.getEq_ID(), fault.getEq_ID() * 100L + 2);
//
//            // faultall
//            Faultall faultall = copyFromFault4Control56(fault);
//            // 2020-10-02 改为按天记录. Time -- EndTime
//            //        int ret = faultallMapper.update(faultall);
//            //        if (ret == 0) {
//            //            faultallMapper.insert(faultall);
//            //        }
//            List<Faultall> faultalls = faultallMapper.selectByEqidDiarltTimeday(faultall);
//            if (faultalls == null || faultalls.isEmpty()) {
//                faultallMapper.insert(faultall);
//                publishFaultall(faultall);
//            } else {
//                Faultall lastfaultall = faultalls.get(0);
//                lastfaultall.setTotalTimes(lastfaultall.getTotalTimes() + 1);
//                lastfaultall.setPeriod(lastfaultall.getPeriod() + fault.getPeriod());
//                lastfaultall.setEndTime(fault.getEndTime());
//                faultallMapper.updateByIdSync(lastfaultall);
//                publishFaultall(lastfaultall);
//            }
            // 2024-05-01 改为缓存
            DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
            dataTypeAndContent.setDataType(SQLDataType.SAVE_FAULT_56);
            dataTypeAndContent.setSaveFaultData(new SaveFaultData(fault, false, 0));
            producer.sendSqlMessage(fault.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));
        }

        // 更新，GZ SX 线网级线路级车站级统计
        updateLatestEquipmentStatusByControl56(fault);
        return ;
    }


    public boolean isInteger(String string){
        Pattern pattern = Pattern.compile("[0-9]+");
        return pattern.matcher(string).matches();
    }

    // 2020-05-25记录fault时候的RMS，4位小数
    // 根据sensorId 对应
    public String getFaultRMS(EquipmentStatus equipmentStatus, int sensorId){
        if (equipmentStatus == null || equipmentStatus.getSensorData()==null || equipmentStatus.getSensorData().isEmpty()
                || sensorId <=0){
            return null;
        }
        for (SensorData sensorData : equipmentStatus.getSensorData()) {
            if ((sensorId == sensorData.getVib_Sensor_No()) && (sensorData.getRMS() != null)) {
                return String.format("%.4f", sensorData.getRMS());
            }
        }
        return null;
    }

    @PostMapping("/getupgradeinfo")
    public byte[] getupgradeinfo(@RequestBody byte[] sendData, HttpServletRequest request) {
        checkInitialOKThrownException();

        try {
            // 用于打印通讯时间和解密前后内容
            printInfo(sendData);

            String mapStr = unCompress(sendData);
            if (PublicVars.printCommunicationInfo == 1 || PublicVars.printEncryptionData == 1) {
                log.info("解密解压后长度：" + mapStr.length());
                log.info("解密解压后内容：" + mapStr);
            }

            Map<String, String> jsonMap = GsonUtils.getGson().fromJson(mapStr, new TypeToken<Map<String, String>>() {
            }.getType());
            Map respBody = new HashMap();

            String upgradeDataJson = jsonMap.get("upgradeData");
            if (upgradeDataJson == null) {
                return null;
            }
            int lineid=0;
            int stationid=0;
            int equipmentid=0;
            String makedate = "";
            String paramtype = "";
            List<Map<String, String>> reqData = GsonUtils.getGson().fromJson(upgradeDataJson, new TypeToken<List<Map<String, String>>>(){}.getType());
            if (reqData != null) {
                for (Map<String, String> map : reqData) { // 应该只有一个
                    lineid = Integer.parseInt(map.get("lineid"));
                    stationid = Integer.parseInt(map.get("stationid"));
                    equipmentid = Integer.parseInt(map.get("equipmentid"));
                    makedate = map.get("makedate"); // 工控机端最大的makedate
                    paramtype = map.get("paramtype");
                };
            }
            if (paramtype == null || paramtype.isEmpty() || makedate == null || makedate.isEmpty() || equipmentid == 0) {
                return null;
            }
            // 智慧城 特殊： 服务器不是最新的。
            boolean isDb2dahuaZHC = false;
            if (hitachi.equalsIgnoreCase(paramtype) && ( equipmentid == 2187202 || equipmentid == 2187203 )) {
                isDb2dahuaZHC = true;
            }

            // 目前 configs / programs 都是按照版本号（datatype）来管理， params 按照 equipmentid 来管理。
            Equipment e1 = PublicVars.getEquipment(equipmentMapper,equipmentid);
            if (e1 == null){
                throw new RuntimeException(String.format("服务器端尚未配置该设备编码 %d , ip: %s (configs配置错误)", equipmentid, request.getRemoteAddr()));
            }
            String programtype="";
            if (e1.getEquipmentSystem() == null || e1.getEquipmentSystem().isEmpty()) {
                if ("single".equalsIgnoreCase(e1.getType())) {
                    programtype = "诊断单驱(通用)";
                } else if ("double".equalsIgnoreCase(e1.getType())) {
                    programtype = "诊断双驱(通用)";
                }
            } else {
                programtype = e1.getEquipmentSystem();
            }


            List<ClientConfigparamsVersion> all = clientConfigparamsVersionDao.queryAllConfigsHitachiByMakedate(equipmentid,makedate,programtype);
            if (all == null || all.isEmpty()) {
                return null;
            }

            // 获取 client_configparams_version -- 根据上传的版本来比较 ？
            // List<ClientConfigparamsVersion> clientConfigsVersions = clientConfigparamsVersionDao.queryConfigsHitachiByMakedate(paramtype,makedate);
            // 2020-07-31: 统一使用 bk2: configs / params / programs 来标识通讯参数、诊断参数 和 程序
            // 2020-07-31: configs/hitachi 其实由前db2...来控制，这里后台只有一个，前端会自动放到 configs/configs4dahua。按版本号来管理

            List<ClientConfigparamsVersion> configs = new ArrayList<>();
            for (ClientConfigparamsVersion item : all){
                if (item.getDatatype() == null || item.getBk2() == null)
                    continue;
                if (programtype.trim().equalsIgnoreCase(item.getDatatype().trim()) && "configs".equalsIgnoreCase(item.getBk2().trim())) {
                    configs.add(item);
                }
            }

            //
            if (configs != null && configs.isEmpty() == false) {
                List<Client_Configs> clientConfigs = clientConfigsDao.getConfigs2(programtype); // 改为版本号
                if (clientConfigs != null && clientConfigs.isEmpty() == false) {
                    respBody.put("ClientConfigsVersion",new Gson().toJson(configs.get(0))); // only one record
                    respBody.put("ClientConfigs",new Gson().toJson(clientConfigs));
                }
            }
            // 只有db2server或者智慧城的2台db2dahua，才更新诊断参数。其他db2dahua不更新，
            // 否则 db2server db2dahua 会 deadloop (智慧城特殊 // DONGWEI: 智慧城不用更新这个参数。智慧城是另外一个做法，通过TXT文件更新)
            boolean checkParamsPrograms = false;
            // 2021-09-26 横沥 要求放开 if (MessageConsumer.configsName.equalsIgnoreCase(paramtype))
                checkParamsPrograms = true;
            if (checkParamsPrograms) {
                // List<ClientConfigparamsVersion> clientParamsVersions = clientConfigparamsVersionDao.queryParamsByMakedate(equipmentid, makedate);
                List<ClientConfigparamsVersion> params = all.stream()
                        .filter(item -> "params".equalsIgnoreCase(item.getDatatype()) && item.getEquipmentid() > 0)
                        .collect(Collectors.toList());

                if (params != null && params.isEmpty() == false) {
                    List<Client_Params> client_params = clientParamsDao.getParams(equipmentid);
                    if (client_params != null && client_params.isEmpty() == false) {
                        respBody.put("ClientParamsVersion", new Gson().toJson(params.get(0)));  // only one record
                        respBody.put("ClientParams", new Gson().toJson(client_params));
                    }
                }

                // 2021-03-07 新增 aiparams / vibparams / publicparams / dmparmas
                List<ClientConfigparamsVersion> aiparams = all.stream()
                        .filter(item -> "aiparams".equalsIgnoreCase(item.getDatatype()) && item.getEquipmentid() > 0)
                        .collect(Collectors.toList());

                if (aiparams != null && aiparams.isEmpty() == false) {
                    List<Client_Ai_Params> client_ai_params = clientAiParamsDao.getParams(equipmentid);
                    if (client_ai_params != null && client_ai_params.isEmpty() == false) {
                        respBody.put("ClientAiParamsVersion", new Gson().toJson(aiparams.get(0)));  // only one record
                        respBody.put("ClientAiParams", new Gson().toJson(client_ai_params));
                    }
                }

                List<ClientConfigparamsVersion> vibparams = all.stream()
                        .filter(item -> "vibparams".equalsIgnoreCase(item.getDatatype()) && item.getEquipmentid() > 0)
                        .collect(Collectors.toList());

                if (vibparams != null && vibparams.isEmpty() == false) {
                    List<Client_Vib_Params> client_vib_params = clientVibParamsDao.getParams(equipmentid);
                    if (client_vib_params != null && client_vib_params.isEmpty() == false) {
                        respBody.put("ClientVibParamsVersion", new Gson().toJson(vibparams.get(0)));  // only one record
                        respBody.put("ClientVibParams", new Gson().toJson(client_vib_params));
                    }
                }

                List<ClientConfigparamsVersion> publicparams = all.stream()
                        .filter(item -> "publicparams".equalsIgnoreCase(item.getDatatype()) && item.getEquipmentid() > 0)
                        .collect(Collectors.toList());

                if (publicparams != null && publicparams.isEmpty() == false) {
                    List<Client_Public_Params> client_public_params = clientPublicParamsDao.getParams(equipmentid);
                    if (client_public_params != null && client_public_params.isEmpty() == false) {
                        respBody.put("ClientPublicParamsVersion", new Gson().toJson(publicparams.get(0)));  // only one record
                        respBody.put("ClientPublicParams", new Gson().toJson(client_public_params));
                    }
                }

                List<ClientConfigparamsVersion> dmparams = all.stream()
                        .filter(item -> "dmparams".equalsIgnoreCase(item.getDatatype()) && item.getEquipmentid() > 0)
                        .collect(Collectors.toList());

                if (dmparams != null && dmparams.isEmpty() == false) {
                    List<Client_Dm_Params> client_dm_params = clientDmParamsDao.getParams(equipmentid);
                    if (client_dm_params != null && client_dm_params.isEmpty() == false) {
                        respBody.put("ClientDmParamsVersion", new Gson().toJson(dmparams.get(0)));  // only one record
                        respBody.put("ClientDmParams", new Gson().toJson(client_dm_params));
                    }
                }
                
            }
//            程序升级分为2步：
//            JAVA程序 升级处理：
//
//            1、hitachi :   检查 db2dahua.war
//            2、configs :   检查   db2server.war, db2mq.war
//            3、2187202/203 : 检查 db2serverzhc.war, db2mq.war, db2dahua.war
//
//            诊断XX 程序
//            1、先从 EQUIPMENT 读取 system
//            2、确定system， 如果不为空，则 system 。否则 根据单驱双驱
//            诊断单驱(通用)
//            诊断双驱(通用)
//            filer要带上这个 system （也就是datatype)

            List<ClientConfigparamsVersion> programs = new ArrayList<>();
            // JAVA
            if (isDb2dahuaZHC) {
                programs = all.stream()
                        .filter(item -> "programs".equalsIgnoreCase(item.getBk2())
                                && ( "db2serverzhc.war".equalsIgnoreCase(item.getProgramlocalname())
                                || "db2mq.war".equalsIgnoreCase(item.getProgramlocalname())
                                || "db2dahua.war".equalsIgnoreCase(item.getProgramlocalname())))
                        .collect(Collectors.toList());
            } else if (MessageConsumer.configsName.equalsIgnoreCase(paramtype)) {
                programs = all.stream()
                        .filter(item -> "programs".equalsIgnoreCase(item.getBk2())
                                && ( "db2server.war".equalsIgnoreCase(item.getProgramlocalname())
                                ||"db2mq.war".equalsIgnoreCase(item.getProgramlocalname())
                                ||"elevator.war".equalsIgnoreCase(item.getProgramlocalname())
                                ||"h485.war".equalsIgnoreCase(item.getProgramlocalname())
                                )
                        )
                        .collect(Collectors.toList());
            } else if (MessageConsumer.hitachi.equalsIgnoreCase(paramtype)) { // dahua可以升级全部
                programs = all.stream()
                        .filter(item -> "programs".equalsIgnoreCase(item.getBk2())
                                && ( "db2dahua.war".equalsIgnoreCase(item.getProgramlocalname())
                                || (upgradeserverfromdh == 1 && "db2server.war".equalsIgnoreCase(item.getProgramlocalname()))
                                || "db2mq.war".equalsIgnoreCase(item.getProgramlocalname())
                                ||"elevator.war".equalsIgnoreCase(item.getProgramlocalname())
                                ||"h485.war".equalsIgnoreCase(item.getProgramlocalname())
                                )
                        )
                        .collect(Collectors.toList());
            }
            if (programs == null) {
                programs = new ArrayList<>();
            }

            // 非 JAVA  : Datatype=版本号 + bk2='programs' + 非'.war'
            if (programtype != null && programtype.isEmpty() == false) {
                for (ClientConfigparamsVersion item : all) {
                    if (programtype.equalsIgnoreCase(item.getDatatype())
                            && "programs".equalsIgnoreCase(item.getBk2())
                            && item.getProgramlocalname().isEmpty() == false
                            && item.getProgramlocalname().indexOf(".war") <0 // java上面已经处理
                    ) {
                        programs.add(item);
                    }
                }
            }
            if (programs != null && programs.isEmpty() == false) {
                respBody.put("ClientProgramsVersion", new Gson().toJson(programs));
            }

            if (respBody.isEmpty() == false) {
                String json = new Gson().toJson(respBody);

                // 2024-07-25 : 记录日志
                UpgradeLog upgradeLog = new UpgradeLog();
                upgradeLog.setCreate_time(LocalDateTime.now());
                upgradeLog.setEquipmentid(equipmentid);
                upgradeLog.setMakedate(makedate);
                upgradeLog.setParamtype(paramtype);
                upgradeLog.setProgramtype(programtype);
                upgradeLog.setParams(json);
                upgradeLogMapper.insert(upgradeLog);

                byte[] responseData=compress(json);
                return responseData;
            }

            return null;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void printInfo(byte[] sendData){
        // 用于打印通讯时间和解密前后内容
        if (PublicVars.printCommunicationInfo == 1) {
            log.info("接收时间：" + LocalDateTime.now());
        }
        if (PublicVars.printCommunicationInfo == 1 || PublicVars.printEncryptionData == 1) {
            //log.info("解密前数据：" + base64Str);
            log.info("解密解压前长度："+sendData.length);
            //log.info(sendData);
        }
    }
    public byte[] compress(String str) throws IOException {
        if (null == str || str.isEmpty()) {
            return null;
        }

        ByteArrayOutputStream baostream = new ByteArrayOutputStream();
        OutputStream outStream = new GZIPOutputStream(baostream);
        outStream.write(str.getBytes("UTF-8"));
        outStream.close();
        byte[] compressedBytes = baostream.toByteArray();
        return compressedBytes;
    }

    @PostMapping("/upload")
    public void upload(@RequestBody byte[] sendData) {
        checkInitialOKThrownException();
        //        if (isreceiver == 1) {
        //            producer.sendMessage(0, producer.QUEUE_UPLOAD_CONSUMER, sendData);
        //            // producer.sendMessageToTopic(producer.TOPIC_UPLOAD_CONSUMER, 0, sendData);
        //            return ;
        //        }

        try {
            // 用于打印通讯时间和解密前后内容
            printInfo(sendData);
            QueueTimes.countUploadP1();
            String mapStr = unCompress(sendData);
            if (PublicVars.printCommunicationInfo == 1 || PublicVars.printEncryptionData == 1) {
                log.info("解密解压后长度：" + mapStr.length());
                log.info("解密解压后内容：" + mapStr);
            }
            // 2024-05-01 改为缓存
            DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
            dataTypeAndContent.setDataType(SQLDataType.UPLOAD_CONFIGS);
            dataTypeAndContent.setData(mapStr);
            producer.sendSqlMessage(queueofsql - 1, producer.QUEUE_SQL, JSON.toJSONString(dataTypeAndContent));

//            Map<String, String> reqBody = GsonUtils.getGson().fromJson(mapStr, new TypeToken<Map<String, String>>() {
//            }.getType());
//
//            List<ClientConfigparamsVersion> clientConfigsVersions;
//            List<Client_Configs> client_configs;
//            List<Client_Params> client_params;
//            List<Client_Ai_Params> client_ai_params;
//            List<Client_Vib_Params> client_vib_params;
//            List<Client_Public_Params> client_public_params;
//            List<Client_Dm_Params> client_dm_params;
//            String sLineid = reqBody.get("lineid");
//            String sStationid = reqBody.get("stationid");
//            String sEquipmentid = reqBody.get("equipmentid");
//            String version = reqBody.get("version");
//            if (version == null)
//                version="no-version";
//            String datatype = reqBody.get("datatype");
//            if (sLineid==null || sLineid.isEmpty() || sStationid==null || sStationid.isEmpty() || sEquipmentid==null || sEquipmentid.isEmpty() || datatype == null || datatype.isEmpty()) {
//                log.error("上传信息缺少：lineid / stationid / equipmentid / datatype");
//                return;
//            }
//            Integer lineid=Integer.parseInt(sLineid);
//            Integer stationid=Integer.parseInt(sStationid);
//            Integer equipmentid=Integer.parseInt(sEquipmentid);
//            DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//            String nowDateTime = dtf2.format(LocalDateTime.now());
//
//            try {
//                versionInfoDao.deleteVerionInfo(equipmentid);
//                versionInfoDao.insertVerionInfo(lineid,stationid,equipmentid,version);
//            } catch (Exception ex) {
//                ex.printStackTrace();
//            }
//
//            // log.error(response);
//            if (reqBody.get("ClientConfigsVersion") != null) {
//                clientConfigsVersions = GsonUtils.getGson().fromJson(reqBody.get("ClientConfigsVersion"), new TypeToken<List<ClientConfigparamsVersion>>() {
//                }.getType());
//
//                if (clientConfigsVersions != null && clientConfigsVersions.isEmpty() == false) {
//                    clientConfigparamsVersionUploadDao.deleteByEquipmentId(equipmentid);
//                    clientConfigsVersions.forEach(item -> {
//                        // bk1 记录时间
//                        item.setBk1(nowDateTime);
//                        clientConfigparamsVersionUploadDao.insert(item);
//                    });
//                }
//            }
//            if (reqBody.get("ClientConfigs") != null) {
//                client_configs = GsonUtils.getGson().fromJson(reqBody.get("ClientConfigs"), new TypeToken<List<Client_Configs>>() {
//                }.getType());
//
//                if (client_configs != null && client_configs.isEmpty() == false) {
//                    // 如果存在，更新。否则insert。原有的保留
//                    clientConfigsUploadDao.deleteByEquipmentIdDataType(equipmentid, client_configs.get(0).getData_type());
//                    client_configs.forEach(item -> {
//                        Client_Configs_Upload itemUpload = new Client_Configs_Upload();
//                        itemUpload.setLineid(lineid);
//                        itemUpload.setStationid(stationid);
//                        itemUpload.setEquipmentid(equipmentid);
//                        itemUpload.setConfig_name(item.getConfig_name());
//                        itemUpload.setConfig_type(item.getConfig_type());
//                        itemUpload.setConfig_value(item.getConfig_value());
//                        itemUpload.setConfig_can_modify(item.getConfig_can_modify());
//                        itemUpload.setRemark(nowDateTime);// 记录当前时间
//                        itemUpload.setData_type(datatype);
//                        clientConfigsUploadDao.insert(itemUpload);
//                    });
//                    logTheUploadTime("Config", lineid, stationid, equipmentid);
//                }
//            }
//            if (reqBody.get("ClientParams") != null) {
//                client_params = GsonUtils.getGson().fromJson(reqBody.get("ClientParams"), new TypeToken<List<Client_Params>>() {
//                }.getType());
//
//                if (client_params != null && client_params.isEmpty() == false) {
//                    clientParamsUploadDao.deleteByEquipmentIdDataType(equipmentid);
//                    client_params.forEach(item -> {
//                        // 这个表没有记录时间字段
//                        // DONGWEI: 工控机 client_params 不能 有 lineid
//                        item.setLineid(lineid);
//                        clientParamsUploadDao.insert(item);
//                    });
//                    logTheUploadTime("Params", lineid, stationid, equipmentid);
//                }
//            }
//            if (reqBody.get("ClientAiParams") != null) {
//                client_ai_params = GsonUtils.getGson().fromJson(reqBody.get("ClientAiParams"), new TypeToken<List<Client_Ai_Params>>() {
//                }.getType());
//
//                if (client_ai_params != null && client_ai_params.isEmpty() == false) {
//                    clientAiParamsUploadDao.deleteByEquipmentId(equipmentid);
//                    client_ai_params.forEach( item -> {
//                        // 这个表没有记录时间字段
//                        // DONGWEI: 工控机 client_ai_params 不能 有 lineid
//                        item.setLineid(lineid);
//                        // 旧版本兼容
//                        /*
//                            alter table client_ai_params add  `RMS_MIN` decimal(12,5) DEFAULT '-20' ;
//                            alter table client_ai_params add  `RMS_MAX` decimal(12,5) DEFAULT '80.00000' ;
//                            alter table client_ai_params add  `Refer_ChanelNum` int(11) NOT NULL DEFAULT '-100' ;
//                            alter table client_ai_params add  `Refer_History` decimal(12,5) DEFAULT '-100' ;
//                            alter table client_ai_params add  `Refer_Value` decimal(12,5) DEFAULT '-100' ;
//                            alter table client_ai_params add  `Bk3` decimal(12,5) DEFAULT NULL ;
//                            alter table client_ai_params add  `Bk4` varchar(100) DEFAULT NULL ;
//                            alter table client_ai_params add  `BD_State` int(11) NOT NULL DEFAULT 0;
//                            alter table client_ai_params add  `BD_Value1` decimal(12,5) DEFAULT 0.00000;
//                            alter table client_ai_params add  `BD_Value2` decimal(12,5) DEFAULT 0.00000;
//                            alter table client_ai_params add  `BD_Value_Dif` decimal(12,5) DEFAULT 0.00000;
//                            alter table client_ai_params add  `BD_Value_Trigger` decimal(12,5) DEFAULT 3.00000;
//                            alter table client_ai_params add  `BD_Value_DifAdd` decimal(12,5) DEFAULT 0.00000;
//                        */
//                        if (item.getRMS_MIN() == null) item.setRMS_MIN(new BigDecimal("-20"));
//                        if (item.getRMS_MAX() == null) item.setRMS_MAX(new BigDecimal("80"));
//                        if (item.getRefer_ChanelNum() == null) item.setRefer_ChanelNum(-100);
//                        if (item.getRefer_History() == null) item.setRefer_History(new BigDecimal("-100"));
//                        if (item.getRefer_Value() == null) item.setRefer_Value(new BigDecimal("-100"));
//                        if (item.getBD_State() == null) item.setBD_State(0);
//                        if (item.getBD_Value1() == null) item.setBD_Value1(new BigDecimal("0.00000"));
//                        if (item.getBD_Value2() == null) item.setBD_Value2(new BigDecimal("0.00000"));
//                        if (item.getBD_Value_Dif() == null) item.setBD_Value_Dif(new BigDecimal("0.00000"));
//                        if (item.getBD_Value_Trigger() == null) item.setBD_Value_Trigger(new BigDecimal("3.00000"));
//                        if (item.getBD_Value_DifAdd() == null) item.setBD_Value_DifAdd(new BigDecimal("0.00000"));
//                        clientAiParamsUploadDao.insert(item);
//                    });
//                    logTheUploadTime("Ai", lineid, stationid, equipmentid);
//                }
//            }
//            if (reqBody.get("ClientVibParams") != null) {
//                client_vib_params = GsonUtils.getGson().fromJson(reqBody.get("ClientVibParams"), new TypeToken<List<Client_Vib_Params>>() {
//                }.getType());
//
//                if (client_vib_params != null && client_vib_params.isEmpty() == false) {
//                    clientVibParamsUploadDao.deleteByEquipmentId(equipmentid);
//                    client_vib_params.forEach(item -> {
//                        // 这个表没有记录时间字段
//                        // DONGWEI: 工控机 client_vib_params 不能 有 lineid
//                        item.setLineid(lineid);
//                        // 旧版本兼容
//                        /*
//                            alter table client_vib_params add  `RMS_MIN` decimal(12,5) DEFAULT '0';
//                            alter table client_vib_params add  `RMS_MAX` decimal(12,5) DEFAULT '12';
//                            alter table client_vib_params add  `Refer_ChanelNum` int(11) NOT NULL DEFAULT '-100';
//                            alter table client_vib_params add  `Refer_History` decimal(12,5) DEFAULT '1.00000';
//                            alter table client_vib_params add  `Refer_Value` decimal(12,5) DEFAULT '-100.00000';
//                         */
//                        if (item.getRMS_MIN() == null) item.setRMS_MIN(new BigDecimal("0"));
//                        if (item.getRMS_MAX() == null) item.setRMS_MAX(new BigDecimal("12"));
//                        if (item.getRefer_ChanelNum() == null) item.setRefer_ChanelNum(-100);
//                        if (item.getRefer_History() == null) item.setRefer_History(new BigDecimal("1.00000"));
//                        if (item.getRefer_Value() == null) item.setRefer_Value(new BigDecimal("-100.00000"));
//                        clientVibParamsUploadDao.insert(item);
//                    });
//                    logTheUploadTime("Vib", lineid, stationid, equipmentid);
//                }
//            }
//            if (reqBody.get("ClientPublicParams") != null) {
//                client_public_params = GsonUtils.getGson().fromJson(reqBody.get("ClientPublicParams"), new TypeToken<List<Client_Public_Params>>() {
//                }.getType());
//
//                if (client_public_params == null || client_public_params.isEmpty()) {
//                    return;
//                }
//                clientPublicParamsUploadDao.deleteByEquipmentId(equipmentid);
//                client_public_params.forEach( item -> {
//                    // 这个表没有记录时间字段
//                    // DONGWEI: 工控机 client_public_params 不能 有 lineid
//                    item.setLineid(lineid);
//                    clientPublicParamsUploadDao.insert(item);
//                    if (item.getEquipmentid() != null && item.getMap_Current() != null) {
//                        PublicVars.mapCurrent.remove(item.getEquipmentid());
//                    }
//                });
//                logTheUploadTime("Public", lineid, stationid, equipmentid);
//            }
//            if (reqBody.get("ClientDmParams") != null) {
//                client_dm_params = GsonUtils.getGson().fromJson(reqBody.get("ClientDmParams"), new TypeToken<List<Client_Dm_Params>>() {
//                }.getType());
//
//                if (client_dm_params != null && client_dm_params.isEmpty() == false) {
//                    clientDmParamsUploadDao.deleteByEquipmentId(equipmentid);
//                    client_dm_params.forEach( item -> {
//                        // 这个表没有记录时间字段
//                        // DONGWEI: 工控机 client_dm_params 不能 有 lineid
//                        item.setLineid(lineid);
//                        clientDmParamsUploadDao.insert(item);
//                    });
//                    logTheUploadTime("Dm", lineid, stationid, equipmentid);
//                }
//            }
            if (PublicVars.isPortalWithData != 1) {
                // upload 数据量少
                producer.sendMessage(0, producer.QUEUE_UPLOAD_PORTAL, sendData);
                // 这个没有IOT
                //producer.sendMessageToTopic(producer.TOPIC_UPLOAD, 0, sendData);
            }
            // 这个无需queue2

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private boolean checkInitialOK(Map respBody) {
        if (!PublicVars.hasApplicationInit) {
            respBody.put("errorCode", 9998);
            respBody.put("errorMsg", "系统正在初始化");
        }
        return PublicVars.hasApplicationInit;
    }
    private void checkInitialOKThrownException() {
        if (!PublicVars.hasApplicationInit) {
            throw new RuntimeException("系统正在初始化");
        }
    }

    @PostMapping("/config/by-name-list")
    public Object getConfigValuesByNameList(@RequestBody List<String> nameList) {
        Map<String, String> resultMap = new HashMap<>();
        if (nameList == null) {
            return resultMap;
        }

        for (String name : nameList) {
            String value = PublicVars.getConfigValue(PublicVars.dbConfigs, name);
            if (value != null) {
                resultMap.put(name, value);
            }
        }
        return resultMap;
    }

    @GetMapping("/last-keep-sensor-data-time/{eqId}")
    public Object getLastKeepSensorDataTimeMapByEqId(@PathVariable("eqId") String eqIdStr) {
        int eqId = Integer.parseInt(eqIdStr);
        return listLastKeepDataTimeByEqId2023(eqId);
    }

    @PostMapping("/serversetting")
    public byte[] serversetting(@RequestBody byte[] sendData) {
        checkInitialOKThrownException();

        try {
            // 用于打印通讯时间和解密前后内容
            printInfo(sendData);

            String mapStr = unCompress(sendData);
            if (PublicVars.printCommunicationInfo == 1 || PublicVars.printEncryptionData == 1) {
                log.info("解密解压后长度：" + mapStr.length());
                log.info("解密解压后内容：" + mapStr);
            }

            Map<String, String> jsonMap = GsonUtils.getGson().fromJson(mapStr, new TypeToken<Map<String, String>>() {
            }.getType());
            Map respBody = new HashMap();

            String severSettingDataJson = jsonMap.get("severSettingData");
            if (severSettingDataJson == null) {
                return null;
            }
//            int lineid=0;
//            int stationid=0;
            int equipmentid=0;
            String realTimeFile = "realTimeFile" ; // default: db2server
            String exceptionMessage = "";
            String exceptionTime = "";
            String fileThreadTime = "";
            List<Map<String, String>> reqData = GsonUtils.getGson().fromJson(severSettingDataJson, new TypeToken<List<Map<String, String>>>(){}.getType());
            if (reqData != null) {
                for (Map<String, String> map : reqData) { // 应该只有一个
//                    lineid = Integer.parseInt(map.get("lineid"));
//                    stationid = Integer.parseInt(map.get("stationid"));
                    equipmentid = Integer.parseInt(map.get("equipmentid"));
                    if (map.containsKey("realTimeFile"))
                        realTimeFile = map.get("realTimeFile"); // maybe: realTimeFile / realTimeFile2  : db2dahua
                    if (map.containsKey("exceptionMessage"))
                        exceptionMessage = map.get("exceptionMessage");
                    if (map.containsKey("exceptionTime"))
                        exceptionTime = map.get("exceptionTime");
                    if (map.containsKey("fileThreadTime"))
                        fileThreadTime = map.get("fileThreadTime");
                    if (map.containsKey("wrongFileInfo")) {
                        wrongFileInfo.put(equipmentid, map.get("wrongFileInfo"));
                    }
                    if (map.containsKey("statusTimeResult")) {
                        statusTimeResult.put(equipmentid, map.get("statusTimeResult"));
                    }
                    if (map.containsKey("db2serverInfo")) {
                        db2serverInfo.put(equipmentid, map.get("db2serverInfo"));
                    }
                };
            }
            if (equipmentid == 0) {
                return null;
            }
            equipmentMessageAll.put(equipmentid, mapStr);
            if (equipmentMessage.isEmpty() || (exceptionMessage != null && exceptionMessage.isEmpty() == false)) {
                equipmentMessage.put(equipmentid, mapStr);
            }

            List<Integer> ftpfiles =  buildFtpAllFilesList(equipmentid);
            if (ftpfiles == null || ftpfiles.isEmpty()) {
                respBody.put(realTimeFile,"0");
            } else {
                respBody.put(realTimeFile,"1");
            }

            if (statusTimeRequest.containsKey(equipmentid)) {
                respBody.put("statusTimeRequest", statusTimeRequest.get(equipmentid));
                statusTimeRequest.remove(equipmentid); // 避免不停传
            }

            if (respBody.isEmpty() == false) {
                String json = new Gson().toJson(respBody);
                byte[] responseData=compress(json);
                return responseData;
            }

            return null;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /*
        if (PublicVars.maintainenceCode.equalsIgnoreCase(control56.getStatuscode().trim())) {
            log.info("entering maintainence mode ...");
            isMaintainenceStatus = 1;
            NormalTimeAterMaintainence = LocalDateTime.now().plusYears(1); //
            needResetTime4CheckMaintainence = true;
            nowStatusCode4CheckMaintainence = "999";
            return true;
        }

        if (isMaintainenceStatus >= 1) {

            // 只要超过 规定分钟数就算维保结束了
            if (NormalTimeAterMaintainence.plusMinutes(PublicVars.maintainenceCheckMinutes).isBefore(control56.getTime())) {
                log.info("leaving maintainence mode ...");
                isMaintainenceStatus = 0;
                return false;
            }

            isMaintainenceStatus ++;
            nowStatusCode4CheckMaintainence = control56.getStatuscode().trim();
            // 检修出现后， 上行 下行 开始计时。
            if (PublicVars.normalStatusCodes.indexOf(","+ nowStatusCode4CheckMaintainence + ",") >= 0) {
                if (needResetTime4CheckMaintainence) {
                    NormalTimeAterMaintainence = control56.getTime(); // 只要上一次不正常都重新开始计时
                    needResetTime4CheckMaintainence = false;
                }
            } else { // 检修出现后，只要非：上行 下行 都认为还是检修阶段。出现非上行 下行则等待下一次上行 下行并重新开始计时。
                needResetTime4CheckMaintainence = true;
                NormalTimeAterMaintainence = LocalDateTime.now().plusYears(1); //
            }
            log.info("keeping maintainence mode ...");
            return true;
        }
     */
    /*
        2021-11-24 采用遥监的规定：
        1、持续正常运行5min以上，对应状态是2、3上下行；（这个是现有做法，改为5分钟即可）
        2、转正常，即状态不是6，计时120min后 （非6即可，就是是故障4也计时。）
        由于可能存在数据堆积后发送，不能以 now() 作为基准时间
        思路：之前等待下一次的control56 过来再做判断有问题。
        实际情况：维保完毕后上行或者下行，然后会一直运行，没有问题的话这天都保持这个状态，下一个状态可能是晚上下班了。
                从而导致这个维保记录一直没法生成。
        修改：增加记录 /data /control56 的时间，以那个时间为准，只要通讯OK就可以判断生成。
             注意判断 time(data) > tim(control56) 才有效。
        然后：将判断是否到时间提取出来单独处理（每隔60秒处理判断一次）
     */
    private boolean isControl56Maintainence(Control56 control56, Equipment e1) {
        Set<String> maintainenceCode =  brandIdMaintainenceCodes.getOrDefault(e1.getBrandid(), Collections.emptySet());
        Set<String> upCode = brandIdUpCodes.getOrDefault(e1.getBrandid(), Collections.emptySet());
        Set<String> downCode = brandIdDownCodes.getOrDefault(e1.getBrandid(), Collections.emptySet());
        Set<String> normalStopCode = brandIdNormalStopCodes.getOrDefault(e1.getBrandid(), Collections.emptySet());

        //空格分开的多个 statusCode
        Set<String> statusCodes = PublicVars.getSetByString(control56.getStatuscode(), " ");

        //if (maintainenceCode.equalsIgnoreCase(control56.getStatuscode())) {
        //if (statusCodes.contains(maintainenceCode)) {
        if (PublicVars.contails(maintainenceCode, statusCodes)) {
            if (isMaintainenceStatus.containsKey(control56.getEquipmentid())) {
                // 维保开始时间以第一次出现6为准 -- 可能出现多次
                return true;
            }

            log.info("entering maintainence mode ...");

            isMaintainenceStatus.put(control56.getEquipmentid(),1);
            // 情况#1： 要等到第一次的 2-3 才能开始计时。先设置1年。
            NormalTimeAterMaintainence.put(control56.getEquipmentid(), control56.getTime().plusYears(1));
            needResetTime4CheckMaintainence.put(control56.getEquipmentid(),true);
            // 情况#2： 每次进入就重新设置规定到期时间120分钟即可。下面只需要判断是否超过这个时间。这个情况不管后续是何种状态，只要不是6维保状态。
            NormalTimeAterMaintainence2.put(control56.getEquipmentid(), control56.getTime().plusMinutes(PublicVars.maintainenceCheckMinutes2));
            return true;
        }
        // 维保中?
        if (
                isMaintainenceStatus.containsKey(control56.getEquipmentid())
                && NormalTimeAterMaintainence.containsKey(control56.getEquipmentid())
                && NormalTimeAterMaintainence2.containsKey(control56.getEquipmentid())
        ) {
//                String nowStatusCode4CheckMaintainence = control56.getStatuscode().trim();
//                if (upCode.equalsIgnoreCase(nowStatusCode4CheckMaintainence) || downCode.equalsIgnoreCase(nowStatusCode4CheckMaintainence)) {
            //if (statusCodes.contains(upCode) || statusCodes.contains(downCode)) {
            if (PublicVars.contails(upCode, statusCodes) || PublicVars.contails(downCode, statusCodes)) {
                    // 情况#1：  从第一次：上行 下行 开始计时。
                    if (needResetTime4CheckMaintainence.containsKey(control56.getEquipmentid())
                            && needResetTime4CheckMaintainence.get(control56.getEquipmentid())) {
                        NormalTimeAterMaintainence.put(control56.getEquipmentid(), control56.getTime().plusMinutes(PublicVars.maintainenceCheckMinutes)); //
                        needResetTime4CheckMaintainence.put(control56.getEquipmentid(), false);
                    }
                    // 本次停止 到 下次状态6 之间可能有多个故障，误报了。维保期间有些是正常跑起来测试，难以避免
                    // 宁可少不能多
//                } else if (PublicVars.normalStopCode.equalsIgnoreCase(nowStatusCode4CheckMaintainence)) {
//                    // 处于维保状态的扶梯，可能开机后只需要观察2--3分钟，不一定足够5分钟，此时也可以结束
//                    NormalTimeAterMaintainence.put(control56.getEquipmentid(), control56.getTime().minusSeconds(1)); // 停机后不再有信号。减少1秒。
//                    needResetTime4CheckMaintainence.put(control56.getEquipmentid(), false);
                //} else if (normalStopCode.equalsIgnoreCase(nowStatusCode4CheckMaintainence) == false) {
            //} else if (statusCodes.contains(normalStopCode)) {
            } else if (PublicVars.contails(normalStopCode, statusCodes)) {
                    // 情况#1：(停止信号不算故障)  检修出现后，只要非：上行 下行 都认为还是检修阶段。出现非上行 下行则等待下一次上行 下行并重新开始计时。
                    needResetTime4CheckMaintainence.put(control56.getEquipmentid(), true);
                    NormalTimeAterMaintainence.put(control56.getEquipmentid(), LocalDateTime.now().plusYears(1)); //
                }

                return true;
        }

        return false;
    }

    private int getSampleSeconds(Integer stationId, Integer lineId){
        // 获取 station(bk2) > line(bk1) > PublicVars.sampleseconds 采用周期
        int sampleseconds = 0;
        {
            Station station = PublicVars.getStation(stationMapper, stationId);
            if (station == null) {
                return -1;
            }
            if (station.getBk2() != null && station.getBk2().isEmpty() == false && isInteger(station.getBk2())) {
                sampleseconds = Integer.parseInt(station.getBk2());
            }
        }
        if (sampleseconds == 0) {
            Line line = PublicVars.getLine(lineMapper, lineId);
            if (line == null) {
                return -2;
            }
            if (line.getBk1() != null && line.getBk1()>0) {
                sampleseconds = line.getBk1();
            }
        }
        if (sampleseconds == 0) {
            sampleseconds = PublicVars.sampleseconds;
        }

        return sampleseconds;
    }

    // 这几个设计原意是从portal端同步给suiteng （保持id的一致性，这样和workbill等可以对应起来）
    // 由于线路端也有这几个表，但是是自我生成，没法从portal同步(id不同)。
    // 线路只需要同步 fault 的修改，尤其是 isFixed 标志。考虑根据 eqid + dlt_rlt + time 定位
    private void publishFault(Fault fault) {
        // 故障转发邮件
        if (!StringUtils.isEmpty(websocket3) && "A".equalsIgnoreCase(fault.getSensortype())) {
            EmailData emailData = new EmailData();
            emailData.setDataType(1);
            emailData.setEqId(fault.getEq_ID());
            emailData.setDiaRlt(fault.getDia_Rlt());
            DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            emailData.setFaultTime(dtf2.format(fault.getEndTime()));
            if (fault.getTime().equals(fault.getEndTime())) {
                emailData.setIsNewFault(1);
            } else {
                emailData.setIsNewFault(0);
            }
            EmailDatalList.emailDatas.add(emailData);
        }

        if (PublicVars.isPortalWithData == 0 || PublicVars.synFaults == 0)
            return ;

        SyncMessage syncMessage = new SyncMessage();
        syncMessage.setTopic(String.format("fault@%d", fault.getDataServerId()));
        syncMessage.setAction(SyncMessage.ACTION_SAVE);
        // 转为和portal一样的格式。
        syncMessage.setContent(JSON.toJSONString(CommonMethod.fault2Fautl4Sync(fault)));
        //syncMessage.setContent(JSON.toJSONString(fault));
        syncMessage.setCreatetime(Timestamp.from(Instant.now()));
        syncMessageMapper.insert(syncMessage);
    }
    private void publishFaultall(Faultall faultall) {
        if (PublicVars.isPortalWithData == 0 || PublicVars.synFaults == 0)
            return ;

        SyncMessage syncMessage = new SyncMessage();
        syncMessage.setTopic(String.format("faultall@%d", faultall.getDataServerId()));
        syncMessage.setAction(SyncMessage.ACTION_SAVE);
        syncMessage.setContent(JSON.toJSONString(faultall));
        syncMessage.setCreatetime(Timestamp.from(Instant.now()));
        syncMessageMapper.insert(syncMessage);
    }
    private void publishLatestFault(Fault fault) {
        return ; // 目前正常情况也有0000，太多了，不同步suiteng

//        if (PublicVars.isPortalWithData == 0 || PublicVars.synFaults == 0)
//            return ;
//
//        SyncMessage syncMessage = new SyncMessage();
//        syncMessage.setTopic(String.format("latestfault@%d", fault.getDataServerId()));
//        syncMessage.setAction(SyncMessage.ACTION_SAVE);
//        //syncMessage.setContent(JSON.toJSONString(fault));
//        syncMessage.setContent(JSON.toJSONString(CommonMethod.fault2Fautl4Sync(fault)));
//        syncMessage.setCreatetime(Timestamp.from(Instant.now()));
//        syncMessageMapper.insert(syncMessage);
    }
    private void publishDeleteLatestFault(int dataserverid, int equipmentid, long beginid) {
        return; // 目前正常情况也有0000，太多了，不同步suiteng

//        if (PublicVars.synFaults == 0)
//            return ;
//
//        SyncMessage syncMessage = new SyncMessage();
//        syncMessage.setTopic(String.format("deletelatestfault@%d", dataserverid));
//        syncMessage.setAction(SyncMessage.ACTION_DELETE);
//        syncMessage.setContent(String.format("%d,%d", equipmentid, beginid));
//        syncMessage.setCreatetime(Timestamp.from(Instant.now()));
//        syncMessageMapper.insert(syncMessage);
    }

    private double getRMSBySensorId(List<SensorData> sensorDatas, int sensorId) {
        for (SensorData sensorData : sensorDatas) {
            if (sensorData.getVib_Sensor_No() == sensorId){
                return sensorData.getRMS();
            }
        }
        return 0;
    }
    // remove all fault
    // set status = 0
    // reformat sensordata
    private void DoReformatData(List<EquipmentStatus> equipmentStatusList) {
        if ("0".equalsIgnoreCase(reformatData))
            return;

        for (EquipmentStatus equipmentStatus : equipmentStatusList) {

            if (reformatfault == 1) {
                equipmentStatus.setStatus(0);
                if (equipmentStatus.getFaults() != null && !equipmentStatus.getFaults().isEmpty()) {
                    equipmentStatus.setFaults(null);
                }
            }

            int index = 0;
            if (equipmentStatus.getSensorData() != null && !equipmentStatus.getSensorData().isEmpty()) {
                for (SensorData sensorData : equipmentStatus.getSensorData()) {
                    index = -1;
                    for (int i = 0; i < reformatSensorIds.length; i++) {
                        if (reformatSensorIds[i].getBaseSensorId() > 0)
                            continue; // round #1
                        if (reformatSensorIds[i].getSensorId() == sensorData.getVib_Sensor_No()) {
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                        continue;

                    if
                    (
                            sensorData.getRMS() < reformatSensorIds[index].getMin()
                            ||
                            sensorData.getRMS() > reformatSensorIds[index].getMax()
                    )
                    sensorData.setRMS(reformatSensorIds[index].getMinValue() + Math.random() * reformatSensorIds[index].getXishu());
                }
            }
            if (equipmentStatus.getSensorData() != null && !equipmentStatus.getSensorData().isEmpty()) {
                for (SensorData sensorData : equipmentStatus.getSensorData()) {
                    index = -1;
                    for (int i = 0; i < reformatSensorIds.length; i++) {
                        if (reformatSensorIds[i].getBaseSensorId() == 0)
                            continue; // round #1
                        if (reformatSensorIds[i].getSensorId() == sensorData.getVib_Sensor_No()) {
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                        continue;

                    sensorData.setRMS(getRMSBySensorId(equipmentStatus.getSensorData(), reformatSensorIds[index].getBaseSensorId()) + reformatSensorIds[index].getMinValue() + Math.random() * reformatSensorIds[index].getXishu());
                }
            }

        }
    }
    @GetMapping("/setReformtData/{reformatData}")
    public String setReformtData(@PathVariable("reformatData") String reformatData) {
        this.reformatData = reformatData;
        return "设置成功";
    }
    @GetMapping("/showReformtData")
    public String showReformtData() {
        this.reformatData = reformatData;
        return "reformatData = " + this.reformatData + " , array=" + new Gson().toJson(reformatSensorIds);
    }
    private Integer getRandomInt() {
        Random r = new Random();
        return r.nextInt(12345) + 8888;
    }
    @GetMapping("/clearallcache")
    public String clearallcache() {
        PublicVars.clearallmap();
        LatestSensorStatusData.clearMap();
        return "OK, equipmentsMap size = " + PublicVars.equipmentsMap.size();
    }
    @GetMapping("/clearequipment")
    public String clearequipment() {
        PublicVars.equipmentsMap.clear();
        return "OK, equipmentsMap size = " + PublicVars.equipmentsMap.size();
    }
    @GetMapping("/showequipment/{stationid}")
    public String showequipment(@PathVariable("stationid") Integer stationid) {
        Set<Equipment> equipments2 = new HashSet<>();
        PublicVars.equipmentsMap.forEach((k, v) -> {
            if (v.getStationId() == stationid || stationid == 0) {
                equipments2.add(v);
            }
        });
        return new Gson().toJson(equipments2);
    }

    @GetMapping("/getupgradeserverfromdh")
    public String getupgradeserverfromdh() {
        return upgradeserverfromdh + "";
    }
    @GetMapping("/setupgradeserverfromdh/{upgradeserverfromdh2}")
    public String setReformtData(@PathVariable("upgradeserverfromdh2") Integer upgradeserverfromdh2) {
        this.upgradeserverfromdh = upgradeserverfromdh2;
        return "设置成功, 最新 = " + this.upgradeserverfromdh;
    }

    @PostMapping("/equipmentfault")
    //public Map syncData(@RequestBody String base64Str) {
    public Map equipmentfault(@RequestBody byte[] sendData, HttpServletRequest request) {
        boolean isEquipmentFaultdh = false;
        Map respBody = new HashMap();
        if (!checkInitialOK(respBody)) {
            return respBody;
        }

        try {
            // 用于打印通讯时间和解密前后内容
            printInfo(sendData);

            String mapStr = unCompress(sendData);
            if (PublicVars.printCommunicationInfo == 1 || PublicVars.printEncryptionData == 1) {
                log.info("解密解压后长度：" + mapStr.length());
                log.info("解密解压后内容：" + mapStr);
            }

            Map<String, String> jsonMap = GsonUtils.getGson().fromJson(mapStr, new TypeToken<Map<String, String>>() {
            }.getType());

            if (jsonMap.containsKey("equipmentFaultDatadh"))
                isEquipmentFaultdh = true;

            String eqDataJson = isEquipmentFaultdh ? jsonMap.get("equipmentFaultDatadh") : jsonMap.get("equipmentFaultData");
            if (eqDataJson == null) {
                log.error(isEquipmentFaultdh ? "数据不合法，没有找到 equipmentFaultDatadh 节点数据 " :"数据不合法，没有找到 equipmentFaultData 节点数据 ");

                respBody.put("errorCode", 1030);
                respBody.put("errorMsg", isEquipmentFaultdh ? "缺少 equipmentFaultDatadh 节点数据 " :"缺少 equipmentFaultData 节点数据 ");
                return respBody;
            }
            List<Fault> equipmentFaults = GsonUtils.getGson().fromJson(eqDataJson, new TypeToken<List<Fault>>() {
            }.getType());


            if (equipmentFaults == null || equipmentFaults.isEmpty()) {
                log.error(isEquipmentFaultdh ? "数据不合法，没有找到 equipmentFaultDatadh 节点数据 " :"数据不合法，没有找到 equipmentFaultData 节点数据 ");

                respBody.put("errorCode", 1030);
                respBody.put("errorMsg", isEquipmentFaultdh ? "缺少 equipmentFaultDatadh 节点数据 " :"缺少 equipmentFaultData 节点数据 ");
                return respBody;
            }

            if (equipmentFaults != null && !equipmentFaults.isEmpty()) {
                for (Fault fault : equipmentFaults) {
                    // saveFault(fault, true, faultInfoMap); // 只有insert ，结构改为和 faultall 一样
                    if (StringUtils.isEmpty(fault.getDia_Rlt())) {
                        continue;
                    }

                    Equipment e1 = PublicVars.getEquipment(equipmentMapper,fault.getEq_ID());
                    if (e1 == null){
                        log.error(String.format("服务器端尚未配置该设备id: %d , ip: %s ", fault.getEq_ID(), request.getRemoteAddr()));

                        respBody.put("errorCode", 1000);
                        respBody.put("errorMsg", "服务器端尚未配置该设备id : " + fault.getEq_ID());
                        return respBody;
                        // throw new RuntimeException("服务器端尚未配置该设备id : " + equipmentStatus.getEq_ID());
                    }

                    fault.setDataServerId(1);
                    fault.setLineid(e1.getLineid());
                    fault.setStation_ID(e1.getStationId());
                    fault.setDeptid(e1.getDeptid());

                    fault.setDataId(0L);
                    fault.setBk1id(0);
                    fault.setBk2id(0L);
                    fault.setBk3id(0L);

                    //新增的 level
                    FaultInfo f1 = PublicVars.getFaultinfo(faultInfoMapper, fault.getDia_Rlt());
                    if (f1 != null) {
                        fault.setDialevel(f1.getDia_Level());
                    } else {
                        fault.setDialevel(0);
                    }

                    if (!isEquipmentFaultdh) {
                        QueueTimes.countEquipmentFaultP1();
                        saveFaultall(fault, true, PublicVars.sampleseconds);
                    } else {
                        QueueTimes.countEquipmentFault_dhP1();
                        saveEquipmentFault_dh(fault, PublicVars.sampleseconds);
                    }
                }
            }

            if (web56 == 1 && sendEqf2Web == 1 && !isEquipmentFaultdh) { // 只处理EquipmentFault
                List<EquipmentFaultSmallDTO> equipmentFaultSmallDTOS = PublicVars.buildEquipmentFaultSmallDTO(equipmentFaults, faultInfoMapper);
                if (equipmentFaultSmallDTOS != null && !equipmentFaultSmallDTOS.isEmpty()) {
                    Latest56AndEqf2Web.saveEquipmentFault(equipmentFaultSmallDTOS);
                }
            }

            // 本地OK再上传
            if (PublicVars.isPortalWithData != 1) {
                producer.sendMessage(equipmentFaults.get(0).getEq_ID() % queueofequipmentfault, producer.QUEUE_EQUIPMENTFAULT_PORTAL, sendData);
            }
            if (queue2ofequipmentfault > 0
                    && ( sendAllid2queue2 || euqipmentids2queue2Set.contains(equipmentFaults.get(0).getEq_ID()))) {
                producer.sendMessage2(equipmentFaults.get(0).getEq_ID() % queue2ofequipmentfault, producer.QUEUE_EQUIPMENTFAULT_PORTAL, sendData);
            }

            respBody.put("errorCode", 0);
            respBody.put("errorMsg", "");

            return respBody;
        } catch (Exception e) {
            e.printStackTrace();

            respBody.put("errorCode", 9999);
            String errorMsg = e.getMessage();
            if (errorMsg == null || errorMsg.isEmpty()) {
                if (e instanceof NullPointerException) {
                    errorMsg = "NullPointerException";

                    StackTraceElement[] stackTrace = e.getStackTrace();
                    if (stackTrace != null && stackTrace.length > 0) {
                        for (int ss = 0; ss < stackTrace.length; ss++) {
                            if ( !StringUtils.isEmpty(stackTrace[ss].getClassName()) && stackTrace[ss].getClassName().indexOf("com.dahua") >= 0) {
                                log.error("异常发生：{} method name : {} , line at: {}", stackTrace[ss].getFileName(), stackTrace[ss].getMethodName(), stackTrace[ss].getLineNumber());
                            }
                        }
                    } else {
                        log.error("e.getStackTrace() returns null");
                    }

                } else {
                    errorMsg = e.toString();
                }
            }
            respBody.put("errorMsg", errorMsg);

            return respBody;
            // throw new RuntimeException(e);
        }
    }

    @GetMapping("/rmsnull")
    public String rmsNullList() {
        if (rmsNullLIst == null || rmsNullLIst.isEmpty())
            return " not found ! ";

        return rmsNullLIst.toString();
    }

    @PostConstruct
    public void MessageConsumerInit() {
        log.info("create_workbill = {}", create_workbill);
        if (!StringUtils.isEmpty(brandids)
                && !StringUtils.isEmpty(beginchars)
                && !StringUtils.isEmpty(up)
                && !StringUtils.isEmpty(down)
                && !StringUtils.isEmpty(normalstop)
                && !StringUtils.isEmpty(maintainence)
                && !StringUtils.isEmpty(numofcode)
        ) {
            String[] strBrandids = brandids.split(" ");
            String[] strBeginchars = beginchars.split(" ");
            String[] strUpCodes = up.split(" ");
            String[] strDownCodes = down.split(" ");
            String[] strNormalStopCodes = normalstop.split(" ");
            String[] strMaintainenceCodes = maintainence.split(" ");
            String[] strNumOfCodes = numofcode.split(" ");
            String[] strNumOfCodesZT = numofcodeZT.split(" ");
            if ((strBrandids.length == strBeginchars.length)
                    && (strBrandids.length == strUpCodes.length)
                    && (strBrandids.length == strDownCodes.length)
                    && (strBrandids.length == strNormalStopCodes.length)
                    && (strBrandids.length == strMaintainenceCodes.length)
                    && (strBrandids.length == strNumOfCodes.length)
                    && (strBrandids.length == strNumOfCodesZT.length)
            ) {
                for (int ii = 0; ii < strBrandids.length; ii++ ) {
                    if (PublicVars.isInteger(strBrandids[ii])) {
                        brandIdBeginChars.put(Integer.parseInt(strBrandids[ii]), strBeginchars[ii]);
                        brandIdUpCodes.put(Integer.parseInt(strBrandids[ii]), PublicVars.str2Set(strUpCodes[ii],";"));
                        brandIdDownCodes.put(Integer.parseInt(strBrandids[ii]), PublicVars.str2Set(strDownCodes[ii],";"));
                        brandIdNormalStopCodes.put(Integer.parseInt(strBrandids[ii]), PublicVars.str2Set(strNormalStopCodes[ii],";"));
                        brandIdMaintainenceCodes.put(Integer.parseInt(strBrandids[ii]), PublicVars.str2Set(strMaintainenceCodes[ii],";"));
                        brandIdNumOfCodes.put(Integer.parseInt(strBrandids[ii]), Integer.parseInt(strNumOfCodes[ii]));
                        brandIdNumOfCodesZT.put(Integer.parseInt(strBrandids[ii]), Integer.parseInt(strNumOfCodesZT[ii]));

                        LatestSensorStatusData.brandIdUpCodes.put(Integer.parseInt(strBrandids[ii]), PublicVars.str2Set(strUpCodes[ii],";"));
                        LatestSensorStatusData.brandIdDownCodes.put(Integer.parseInt(strBrandids[ii]), PublicVars.str2Set(strDownCodes[ii],";"));
                        LatestSensorStatusData.brandIdNormalStopCodes.put(Integer.parseInt(strBrandids[ii]), PublicVars.str2Set(strNormalStopCodes[ii],";"));
                        LatestSensorStatusData.brandIdMaintainenceCodes.put(Integer.parseInt(strBrandids[ii]), PublicVars.str2Set(strMaintainenceCodes[ii],";"));

                    }
                }
            } else {
                log.error("strBrandids.length != ...length");
            }
        }
        if (hitachiBrandid == null) {
            hitachiBrandid = 0;
        }
        checkSend2Queue2();
        checkControl56FaultStatusCode();

        log.info("allruncodes = {}, allstopcodes = {}, data.FT.runningtimecounttype={}, data.ZT.runningtimecounttype={}", allruncodes, allstopcodes, runnintTimeCountType, runnintTimeCountTypeZT);
        PublicVarsTimeDay.setRunStopCodes(allruncodes, allstopcodes);
        runnintTimeCountType = RunningTimeCoutType.getRunningTimeCountType(runningtimecounttypeSetting);
        runnintTimeCountTypeZT = RunningTimeCoutType.getRunningTimeCountType(runningtimecounttypeSettingZT);
        log.info("brandIdNumOfCodes={}, brandIdNumOfCodesZT={}, brandIdBeginChars = {}, brandIdUpCodes = {}, brandIdDownCodes={}, brandIdNormalStopCodes={}, brandIdMaintainenceCodes={}", brandIdNumOfCodes, brandIdNumOfCodesZT, brandIdBeginChars, brandIdUpCodes, brandIdDownCodes, brandIdNormalStopCodes,brandIdMaintainenceCodes);
        log.info("allruncodes = {}, allstopcodes = {}, data.FT.runningtimecounttype={}, data.ZT.runningtimecounttype={}", allruncodes, allstopcodes, runnintTimeCountType, runnintTimeCountTypeZT);
    }
    private void checkSend2Queue2() {
        if (send2queue2 == null || send2queue2 != 1) {
            return;
        }
        if (StringUtils.isEmpty(euqipmentids2queue2)) {
            return;
        }
        String[] ids = euqipmentids2queue2.split(" ");
        if (ids == null || ids.length == 0) {
            return;
        }
        for (String id : ids) {
            if ("000000".equals(id)) {
                sendAllid2queue2 = true;
                return;
            }
            if (isInteger(id)) {
                euqipmentids2queue2Set.add(Integer.parseInt(id));
            }
        }
    }
    private void checkControl56FaultStatusCode() {
        List<Control56config> configs = control56configMappper.getControl56configs();
        if (configs == null || configs.isEmpty()) {
            return;
        }
        //
        for (Control56config config : configs) {
            //if ("状态".equals(config.getControltype()) && "故障".equals(config.getControlinfo())) {
                control56_fault_statuscodeSet.add(config.getControlcode());
            //}
        }
    }

    public void countEnergy4SlowRun(EquipmentStatus equipmentStatus) {
        if (equipmentStatus == null || equipmentStatus.getPeriod() <= 0)
            return ;

        Double energy = 0d;
        double current = PublicVars.getMapCurrent(clientPublicParamsUploadDao, equipmentStatus.getEq_ID());

        energy = 1.732 * volt * current * energyxishu * equipmentStatus.getPeriod() / 3600.0 / 1000;

        // 双驱 ？ 2倍
        Equipment e = PublicVars.getEquipment(equipmentMapper, equipmentStatus.getEq_ID());
        if ( e == null)
            return ;
        if ("double".equalsIgnoreCase(e.getType())) {
            energy = energy * 2;
        }

        //放入队列。让另一个线程来计算和处理。以避免冲突
        if (energy > 0.0001) {
            Consumeenergy consumeenergy = new Consumeenergy();
            consumeenergy.setLineid(equipmentStatus.getLineid());
            consumeenergy.setStationid(equipmentStatus.getStation_ID());
            consumeenergy.setEquipmentid(equipmentStatus.getEq_ID());
            consumeenergy.setDeptid(equipmentStatus.getDeptid());
            consumeenergy.setBk2(equipmentStatus.getBk2());
            consumeenergy.setBk5(equipmentStatus.getBk5());
            consumeenergy.setValue(energy);
            consumeenergy.setTime(LocalDateTime.of(equipmentStatus.getTime().getYear(), equipmentStatus.getTime().getMonthValue(), equipmentStatus.getTime().getDayOfMonth(), equipmentStatus.getTime().getHour(), 0));//转为小时
            consumeenergy.setYyyy(equipmentStatus.getTime().getYear());
            consumeenergy.setYyyymm(equipmentStatus.getTime().getYear() * 100 + equipmentStatus.getTime().getMonthValue());
            // bk1id 存放日期 yyyymmdd ，便于统计
            consumeenergy.setBk1id(consumeenergy.getYyyymm() * 100 + equipmentStatus.getTime().getDayOfMonth());
            consumeenergy.setEndtime(equipmentStatus.getTime()); // StartTime待insert
            // SchedulingConfig.energyQueue.add(consumeenergy);
            producer.sendEnergy(JSON.toJSONString(consumeenergy));
        }
    }

    @GetMapping("/sensordata/{eqId}")
    public String getSensorData(@PathVariable("eqId") Integer eqId) {
        int sessionIndex = 0;
        if (!LatestSensorStatusData.latestSensorStatusSend[sessionIndex].containsKey(eqId)) {
            return "not found in latestSensorStatusSend ";
        }
        StringBuffer sb = new StringBuffer("Send = ");
        sb.append(LatestSensorStatusData.latestSensorStatusSend[sessionIndex].get(eqId));
        sb.append(" ---- ");
        sb.append(JSON.toJSONString(LatestSensorStatusData.latestSensorStatusData.get(eqId)));
        return sb.toString();
    }
    @GetMapping("/allsensordata")
    public String getAllSensorData() {
        if (LatestSensorStatusData.latestSensorStatusSend[0].isEmpty()) {
            return "no data in latestSensorStatusSend ";
        }
        StringBuffer sb = new StringBuffer();
        sb.append(" --[0]-- ");
        sb.append(JSON.toJSONString(LatestSensorStatusData.latestSensorStatusSend[0]));
        sb.append(" --[1]-- ");
        sb.append(JSON.toJSONString(LatestSensorStatusData.latestSensorStatusSend[1]));
        sb.append(" --[data]-- ");
        sb.append(JSON.toJSONString(LatestSensorStatusData.latestSensorStatusData));
        return sb.toString();
    }

    //记录时间
//    private void logTheUploadTime(String datatype, Integer lineid, Integer stationid, Integer equipmentid) {
//        if (PublicVars.isPortalWithData != 1) {
//            return;
//        }
//        Client_AiVibPublicDm_UploadTime client_aiVibPublicDm_uploadTime = new Client_AiVibPublicDm_UploadTime();
//        client_aiVibPublicDm_uploadTime.setDatatype(datatype);
//        client_aiVibPublicDm_uploadTime.setLineid(lineid);
//        client_aiVibPublicDm_uploadTime.setStationid(stationid);
//        client_aiVibPublicDm_uploadTime.setEquipmentid(equipmentid);
//        client_aiVibPublicDm_uploadTime.setMakedate(Timestamp.valueOf(LocalDateTime.now()));
//        if (clientAiVibPublicDmUploadTimeDao.updateByEquipmentIdDataType(client_aiVibPublicDm_uploadTime) <= 0) {
//            clientAiVibPublicDmUploadTimeDao.insert(client_aiVibPublicDm_uploadTime);
//        }
//    }

    private Integer checkElevatorStatus(String statusName, String[] statusCodes) {
        if (statusCodes == null || statusCodes.length == 0 || !PublicVars.elevatorStatusConfigs.containsKey(statusName)) {
            return 0;
        }
        for (String statusCode : statusCodes) {
            if (PublicVars.elevatorStatusConfigs.get(statusName).indexOf(statusCode) >= 0) {
                return 1;
            }
        }
        return 0;
    }

    private Elevator fromControl56(Control56 control56, Equipment e) {
        Control56 oldControl56= lastControl56s.get(control56.getEquipmentid());
        if (oldControl56 != null && oldControl56.getStatuscode().equals(control56.getStatuscode())
                && oldControl56.getFaultcode().equals(control56.getFaultcode())
        ) {
            return null;
        }

        Elevator elevator = new Elevator();

        elevator.setLineid(e.getLineid());
        elevator.setStationid(e.getStationId());
        elevator.setEquipmentid(e.getId());
        elevator.setTime(control56.getTime());
        elevator.setDeptid(e.getDeptid());
        elevator.setStatuscode(control56.getStatuscode());
        elevator.setFaultcode(control56.getFaultcode());
        // select * from  client_params 每台电梯都可能不同
        elevator.setFloor(PublicVars.getElevatorFloor(clientParamsDao, e.getId(), control56.getCode15()));
        elevator.setMqsendstatus(0);
        elevator.setServersendstatus(0);
        elevator.setBk4(e.getBk2());

        // 由于直梯状态码唯一，not like 扶梯有简单的 2、3等，因此只需要用 indexOf包含比较
        String[] statusCodes = control56.getStatuscode() == null ? null : control56.getStatuscode().split(" ");
        elevator.setStatusup(checkElevatorStatus("up", statusCodes));
        elevator.setStatusdown(checkElevatorStatus("down", statusCodes));
        elevator.setStatusstop(checkElevatorStatus("stop", statusCodes));
        elevator.setStatusfault(checkElevatorStatus("fault", statusCodes));
        elevator.setStatusmaintenance(checkElevatorStatus("maintainence", statusCodes));
        elevator.setStatuslock(checkElevatorStatus("lock", statusCodes));
        elevator.setStatusalarm(checkElevatorStatus("alarm", statusCodes));

        elevator.setStatusbk0(checkElevatorStatus("statusbk0", statusCodes));
        elevator.setStatusbk1(checkElevatorStatus("statusbk1", statusCodes));
        elevator.setStatusbk2(checkElevatorStatus("statusbk2", statusCodes));
        elevator.setStatusbk3(checkElevatorStatus("statusbk3", statusCodes));
        elevator.setStatusbk4(checkElevatorStatus("statusbk4", statusCodes));
        elevator.setStatusbk5(checkElevatorStatus("statusbk5", statusCodes));
        elevator.setStatusbk6(checkElevatorStatus("statusbk6", statusCodes));
        elevator.setStatusbk7(checkElevatorStatus("statusbk7", statusCodes));

        elevator.setCode1(control56.getCode1());
        elevator.setCode2(control56.getCode2());
        elevator.setCode3(control56.getCode3());
        elevator.setCode4(control56.getCode4());
        elevator.setCode5(control56.getCode5());
        elevator.setCode6(control56.getCode6());

        // 这个字段用于控制是否永久保存数据：故障 乘客报警 维保保存
        if (elevator.getStatusfault() == 1
                || elevator.getStatusalarm() == 1
                || elevator.getStatusmaintenance() == 1
        ) {
            elevator.setStatusbk8(1);
        } else
            elevator.setStatusbk8(0);

        return elevator;
    }

    private boolean checkStringSame(String s1, String s2) {
        if (StringUtils.isEmpty(s1)  && StringUtils.isEmpty(s2) ) {
            return true;
        }
        if (StringUtils.isEmpty(s1)  && !StringUtils.isEmpty(s2)) {
            return false;
        }
        if (!StringUtils.isEmpty(s1)  && StringUtils.isEmpty(s2)) {
            return false;
        }
        return s1.equals(s2);
    }
    private void saveElevatorData(Control56 control56, Equipment e, String type) {
        Elevator elevator = fromControl56(control56, e);
        if (elevator == null) {
            return;
        }

        LatestSensorStatusData.latest56.put(control56.getEquipmentid(), control56);
        LatestSensorStatusData.hasLatest56.put(control56.getEquipmentid(), 1);

//        boolean sameAsLast = false;
//        if (lastElevators.containsKey(elevator.getEquipmentid())) {
//            Elevator lastElevator=  lastElevators.get(elevator.getEquipmentid());
//            if (checkStringSame(lastElevator.getStatuscode(), elevator.getStatuscode())
//                    && checkStringSame(lastElevator.getFaultcode(), elevator.getFaultcode())
//                    && checkStringSame(lastElevator.getFloor(), elevator.getFloor())
//            ) {
//                sameAsLast = true;
//            }
//        }
//        if (!sameAsLast) {
        //elevatorMapper.insert(elevator);
            // 2024-05-01 改为缓存
        QueueTimes.count56zP1();
        DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
        dataTypeAndContent.setDataType(SQLDataType.ELEVATOR);
        dataTypeAndContent.setElevator(elevator);
        producer.sendSqlMessage(elevator.getEquipmentid() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));

            lastElevators.put(elevator.getEquipmentid(), elevator);
//        }

        if (web56 == 1) {
            Control56SmallDTO control56SmallDTO = PublicVars.buildControl56Small(control56, control56configMappper);
            if (control56SmallDTO != null) {
                control56SmallDTO.setElevator(elevator);

                Latest56AndEqf2Web.saveControl56(control56SmallDTO);
                /* 改为 WS 发送
                SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
                requestFactory.setConnectTimeout(30000); //设置超时
                requestFactory.setReadTimeout(60000);
                RestTemplate restTemplate = new RestTemplate(requestFactory);
                //RestTemplate restTemplate = new RestTemplate();
                String url = PublicVars.serverBaseUrl + "/control56InMemory";
                try {
                    restTemplate.put(url, control56SmallDTO);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                // System.out.println(url);
                 */
            }
        }

    }

    /**
     * 保存fault相关表
     * @param elevator
     * @param f1
     * @param e1
     */
    private void saveFault4Elevator(Elevator elevator, FaultInfo f1, Equipment e1) {
        if (elevator==null || f1==null || elevator.getStatusfault() == 0){
            // System.out.println("fault is null || faultInfo==null || elevator.getStatusfault() == 0");
            return ;
        }

        Fault fault = new Fault();
        fault.setDataServerId(0);
        fault.setDataId(0L);
        fault.setStation_ID(elevator.getStationid());
        fault.setEq_ID(elevator.getEquipmentid());
        fault.setDeptid(elevator.getDeptid());
        fault.setDia_Rlt(elevator.getFaultcode());
        fault.setDialevel(f1.getDia_Level());
        fault.setLineid(elevator.getLineid());
        fault.setTime(elevator.getTime());
        fault.setTotalTimes(1);
        fault.setPeriod(PublicVars.sampleseconds);
        fault.setEndTime(elevator.getTime());

        fault.setBk3id(System.currentTimeMillis());
        fault.setBk1id(0);
        fault.setBk2id(0L);

        fault.setBk2(e1.getBk2()); // 设备类型
        fault.setBk5(e1.getBk5()); // 设备分级

        fault.setSensortype(f1.getRemark());
        fault.setBk1(f1.getFaultclass()); // 故障分类
        fault.setBk4(elevator.getBk4()); // 故障类型：扶梯设备、扶梯安全开关、直梯设备

        //新增加的几个字段：品牌、分类等
        fault.setEquipmentbrandid(e1.getBrandid());
        // 是否有合法的传感器id
        if (f1!=null){
            Sensor sensor = PublicVars.getSensorinfo(sensorMapper,f1.getPartcode());
            if (sensor != null){
                fault.setSensorid(sensor.getID());
                // No rms
                // fault.setSensortype(sensor.getSensor_type());
                fault.setPartgroupid(sensor.getPartgroupid());
                // 继续找设备部件+部件
                Equipmentparts equipmentparts =PublicVars.getEquipmentpartsInfo(equipmentpartsMapper,fault.getEq_ID(),fault.getSensorid());
                if (equipmentparts!=null){
                    fault.setPartid(equipmentparts.getPartid());
                    Part part = PublicVars.getPartinfo(partMapper,equipmentparts.getPartid());
                    if (part !=null){
                        fault.setPartbrandid(part.getBrandid());
                        fault.setSupplierid(part.getSupplierid());
                    }
                }
            }
        }

//        //已经配置返回 id
//        faultMapper.insert(fault);
//        fault.setBk3id(fault.getID());
//        faultMapper.updateBk3id(fault.getBk3id(),fault.getID());
//
//        fault.setIsFixed(0);
//        fault.setIsChecked(0);
//        fault.setIsReceived(0);
//        publishFault(fault);
//
//        // latestfault
//        //latestFaultMapper.deleteLatestFaultByStationIdAndEqId(fault.getStation_ID(), fault.getEq_ID());
//        fault.setID(fault.getEq_ID()*100L + 1);
//        if (latestFaultMapper.updateLatestFault(fault) <= 0) {
//            latestFaultMapper.insertLatestFault(fault);
//        }
//        publishLatestFault(fault);
//        latestFaultMapper.deleteLatestFaultByEqIdAndId(fault.getEq_ID(),fault.getEq_ID() * 100L + 2);
//        publishDeleteLatestFault(fault.getDataServerId(), fault.getEq_ID(),fault.getEq_ID() * 100L + 2);
//
//        // faultall
//        Faultall faultall = copyFromFault4Control56(fault);
//        // 2020-10-02 改为按天记录. Time -- EndTime
//        //        int ret = faultallMapper.update(faultall);
//        //        if (ret == 0) {
//        //            faultallMapper.insert(faultall);
//        //        }
//        List<Faultall> faultalls = faultallMapper.selectByEqidDiarltTimeday(faultall);
//        if (faultalls == null || faultalls.isEmpty()) {
//            faultallMapper.insert(faultall);
//            publishFaultall(faultall);
//        } else {
//            Faultall lastfaultall = faultalls.get(0);
//            lastfaultall.setTotalTimes(lastfaultall.getTotalTimes() + 1);
//            lastfaultall.setPeriod(lastfaultall.getPeriod() + fault.getPeriod());
//            lastfaultall.setEndTime(fault.getEndTime());
//            faultallMapper.updateByIdSync(lastfaultall);
//            publishFaultall(lastfaultall);
//        }
        // 2024-05-01 改为缓存
        DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
        dataTypeAndContent.setDataType(SQLDataType.SAVE_FAULT_ELEVATOR);
        dataTypeAndContent.setSaveFaultData(new SaveFaultData(fault, false, 0));
        producer.sendSqlMessage(fault.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));
        return ;
    }
    private void FTControl56(Control56 control56, Map respBody, Equipment e1) {
        // 维保判断用
        if (    isMaintainenceStatus.containsKey(control56.getEquipmentid())) {

            LatestSensorStatusData.hasControl56Fault.put(control56.getEquipmentid(), 0);
            LatestSensorStatusData.latest56Fault.remove(control56.getEquipmentid());

            if ( !latestData_56Time.containsKey(control56.getEquipmentid())
                    ||  latestData_56Time.get(control56.getEquipmentid()).isBefore(control56.getTime()) )
                latestData_56Time.put(control56.getEquipmentid(), control56.getTime());
        }

        // 这几个字段收到的时候是NULL，先设置
        control56.setMqsendstatus(0);
        control56.setServersendstatus(0);
        control56.setEndtime(control56.getTime());
        control56.setPeriod(0); // 改为秒.默认20秒
        control56.setTotaltimes(1);

        // Hitachi FT 必须填写，工控机上传
        if (hitachiBrandid.equals(e1.getBrandid())
                && ("FT".equalsIgnoreCase(e1.getBk2()) || "FT2".equalsIgnoreCase(e1.getBk2()))) {
            // statuscode 智慧城送了 空 上来: 2021-05-26，工控机也写入 空白
            // 必须确保整数，否则 Control56SmallDTO 出错
            if (control56.getStatuscode() == null || control56.getStatuscode().isEmpty() || !isInteger(control56.getStatuscode())) {
                control56.setStatuscode("0");
            } else if (isInteger(control56.getStatuscode()) && Integer.parseInt(control56.getStatuscode()) == 0) {
                control56.setStatuscode("0");
            }

            // faultcode 可能乱，空格，0 , 00, 000, 0000 都有可能，为了统一，这个两个都设置为 0，control56中也只配置0
            if (control56.getFaultcode() == null || control56.getFaultcode().isEmpty()) {
                control56.setFaultcode("0");
            } else if (isInteger(control56.getFaultcode()) && Integer.parseInt(control56.getFaultcode()) == 0) {
                control56.setFaultcode("0");
            }
            // 防止乱码。直接丢弃。
            Pattern pattern = Pattern.compile("^[a-zA-Z0-9]+$");
            if  (!pattern.matcher(control56.getStatuscode()).matches() || !pattern.matcher(control56.getFaultcode()).matches()) {
                log.error("非法字符 = {} {} {} {} ", control56.getEquipmentid(), control56.getTime(), control56.getStatuscode(), control56.getFaultcode());
                respBody.put("errorCode", 0);
                respBody.put("errorMsg", "");
                return;
            }
        } else if (GRbrandid.equals(e1.getBrandid())
                && ("FT".equalsIgnoreCase(e1.getBk2()) || "FT2".equalsIgnoreCase(e1.getBk2()))) {
            /* 广日的不是整数
            GRS0	状态	停止
            GRS1	状态	上行
            GRS2	状态	下行
            GRS3	状态	检修
            GRS4	状态	故障
             */
            if (StringUtils.isEmpty(control56.getStatuscode())) {
                log.error("状态码为空 = {} {} {} {} ", control56.getEquipmentid(), control56.getTime(), control56.getStatuscode(), control56.getFaultcode());
                respBody.put("errorCode", 0);
                respBody.put("errorMsg", "");
                return;
            }
            if (StringUtils.isEmpty(control56.getFaultcode())) {
                log.error("故障码为空 = {} {} {} {} ", control56.getEquipmentid(), control56.getTime(), control56.getStatuscode(), control56.getFaultcode());
                respBody.put("errorCode", 0);
                respBody.put("errorMsg", "");
                return;
            }
            // GR 用 GR0表示，转为0
            if ("GR0".equalsIgnoreCase(control56.getFaultcode())) {
                control56.setFaultcode("0");
            }
        } else if (SLbrandid.equals(e1.getBrandid())
                && ("FT".equalsIgnoreCase(e1.getBk2()) || "FT2".equalsIgnoreCase(e1.getBk2()))) {
            /*
                三菱： Code1 Code2 : 状态(点表）
                Code3 / 4 / 5 /6 /7 : 故障码，需要转为16进制，不足4位的前面补0，例如 00F9
             */
            // 其他扶梯 + 直梯 ， 通过计算点位得到 : 确保 statusCode faultCode 不会是空
            Integer[] codes = new Integer[] {
                    control56.getCode1(),control56.getCode2()
            };
            String[] statusFaultCode = PublicVars.getStatusCodeFaultCodeFromCode16(codes, brandIdBeginChars.get(e1.getBrandid()), control56configMappper, brandIdNumOfCodes.get(e1.getBrandid()), e1);
            if (statusFaultCode == null || statusFaultCode.length != 2) {
                control56.setStatuscode("0");
                control56.setFaultcode("0");
            } else {
                control56.setStatuscode(StringUtils.isEmpty(statusFaultCode[0]) ? "0" : statusFaultCode[0]);
                control56.setFaultcode(StringUtils.isEmpty(statusFaultCode[1]) ? "0" : statusFaultCode[1]);
            }
            String code3 = PublicVars.sanlingFaultCode(control56.getCode3(), brandIdBeginChars.get(e1.getBrandid()), 3, e1);
            String code4 = PublicVars.sanlingFaultCode(control56.getCode4(), brandIdBeginChars.get(e1.getBrandid()), 4, e1);
            String code5 = PublicVars.sanlingFaultCode(control56.getCode5(), brandIdBeginChars.get(e1.getBrandid()), 5, e1);
            String code6 = PublicVars.sanlingFaultCode(control56.getCode6(), brandIdBeginChars.get(e1.getBrandid()), 6, e1);
            String code7 = PublicVars.sanlingFaultCode(control56.getCode7(), brandIdBeginChars.get(e1.getBrandid()), 7, e1);
            // 目前数据库没有7，只有 code1--6，有必要再加

            String slFaultCode = String.format("%s %s %s %s %s", code3, code4, code5, code6, code7);
            if (slFaultCode == null)
                slFaultCode = "";
            slFaultCode = slFaultCode.trim();

            if (StringUtils.isEmpty(slFaultCode)) {
                slFaultCode = "0";
            }
            control56.setFaultcode(slFaultCode);
        } else if (otisBrandid.equals(e1.getBrandid())) {
            // otis扶梯 : Code1 丢弃，这里从2开始 此处不需要带入 Code3
            Integer[] codes = new Integer[] {
                    control56.getCode1(),control56.getCode2(),0,control56.getCode4(),control56.getCode5(),control56.getCode6(),
                    control56.getCode7(),control56.getCode8(),control56.getCode9(),control56.getCode10(),control56.getCode11(),
                    control56.getCode12(),control56.getCode13(),control56.getCode14(),control56.getCode15()
            };
            log.info("codes = {}", new Gson().toJson(codes));
            // log.info("brandIdBeginChars = {}, brandIdNumOfCodes = {}, e1.getBrandid= {}", new Gson().toJson(brandIdBeginChars), new Gson().toJson(brandIdNumOfCodes), e1.getBrandid());
            String[] statusFaultCode = PublicVars.getStatusCodeFaultCodeFromCode16(codes, brandIdBeginChars.get(e1.getBrandid()), control56configMappper, brandIdNumOfCodes.get(e1.getBrandid()), e1);
            if (statusFaultCode == null || statusFaultCode.length != 2) {
                control56.setStatuscode("0");
                control56.setFaultcode("0");
            } else {
                control56.setStatuscode(StringUtils.isEmpty(statusFaultCode[0]) ? "0" : statusFaultCode[0]);
                control56.setFaultcode(StringUtils.isEmpty(statusFaultCode[1]) ? "0" : statusFaultCode[1]);
            }
            Integer fuyi = 65535;
            Integer NoError = 255;
            Integer code3 = control56.getCode3(); // 从40000开始，实际上是4
            if (fuyi.equals(code3) ||
                    (StringUtils.isEmpty(e1.getBk80()) && (NoError.equals(code3) || !control56.getStatuscode().contains("OF-1-3")) )) { // A版本只判断故障状态？
                control56.setFaultcode("0");
            } else if (code3 != null) {
                String otisFaultCode = String.format("OF%s-3-%s"
                        , StringUtils.isEmpty(e1.getBk80()) ? "" : e1.getBk80().trim()
                        , code3);
                FaultInfo of = PublicVars.getFaultinfo(faultInfoMapper, otisFaultCode);
                if (of != null) {
                    control56.setFaultcode(otisFaultCode);
                } else {
                    control56.setFaultcode("0");
                }
            } else {
                control56.setFaultcode("0");
            }
        } else {
            // 其他扶梯 + 直梯 ， 通过计算点位得到 : 确保 statusCode faultCode 不会是空
            Integer[] codes = new Integer[] {
                    control56.getCode1(),control56.getCode2(),control56.getCode3(),control56.getCode4(),control56.getCode5(),
                    control56.getCode6(),control56.getCode7(),control56.getCode8(),control56.getCode9(),control56.getCode10(),
                    control56.getCode11(),control56.getCode12(),control56.getCode13(),control56.getCode14(),control56.getCode15()
            };
            String[] statusFaultCode = PublicVars.getStatusCodeFaultCodeFromCode16(codes, brandIdBeginChars.get(e1.getBrandid()), control56configMappper, brandIdNumOfCodes.get(e1.getBrandid()), e1);
            if (statusFaultCode == null || statusFaultCode.length != 2) {
                control56.setStatuscode("0");
                control56.setFaultcode("0");
            } else {
                control56.setStatuscode(StringUtils.isEmpty(statusFaultCode[0]) ? "0" : statusFaultCode[0]);
                control56.setFaultcode(StringUtils.isEmpty(statusFaultCode[1]) ? "0" : statusFaultCode[1]);
            }
        }

        //新增的 lineid, stationid, deptid, 根据Eq_id --> Station --> Line
        control56.setDataserverid(PublicVars.dataServerId);
        control56.setDataid(0L);

        // 维修状态不处理, 但是要记录，方便统计维保情况
        isControl56Maintainence(control56, e1);

        // 需要进行合法性判断：所有合法的 controlcode, controlstatus都在 control56config 表中配置
        /* 先保存。以免客户端 deadloop
        Control56config statusControl56config = PublicVars.getControl56config(control56configMappper ,control56.getStatuscode().toString());
        if (statusControl56config == null){  // 搞不清，先判断 || !"状态".equalsIgnoreCase(statusControl56config.getControltype())
            throw new RuntimeException("服务器端control56config尚未配置该状态码");
        }
        Control56config faultControl56config = PublicVars.getControl56config(control56configMappper ,control56.getFaultcode());
        if (faultControl56config == null){
            throw new RuntimeException("服务器端control56config尚未配置该故障码");
        }
        */

        // 首先判断是否是需要统计的错误，如果是，插入fault...
        // 2023-05-21 点表-故障码可能多个
        String[] faultCodes = PublicVars.getArrayByString(control56.getFaultcode(), " ");
        boolean hasUpdatedLatestEquipmentStatus = false;
        for (int k = 0; k < faultCodes.length; k++) {
            if ("0".equalsIgnoreCase(faultCodes[k])) {
                continue;
            }
            FaultInfo f1 = PublicVars.getFaultinfo(faultInfoMapper, faultCodes[k]);
            // 如果状态码4 （故障），此时有可能故障码不存在。需要记录。同时还是需要生成fault数据
            // 控制板经常升级 -- 部分故障码可能没录入系统。---> 目前只有 HITACHI 才可能有这个情况。通力的没找到就不会写入了。
            if (f1 == null) {
                if (PublicVars.isPortalWithData == 1) {
                    DataLog log = new DataLog();
                    log.setCreate_time(LocalDateTime.now());
                    log.setDescription("控制类代码未定义");
                    log.setMethod(control56.getEquipmentid().toString());
                    log.setParams(faultCodes[k]);
                    log.setTime(1L);
                    log.setLog_type("FAULT");
                    log.setUsername("");
                    DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    log.setException_detail(dtf2.format(log.getCreate_time())); // recent time
                    // 2024-05-01 改为缓存
//                    if (dataLogMapper.update(log) <= 0) {
//                        dataLogMapper.insert(log);
//                    }
                    DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                    dataTypeAndContent.setDataType(SQLDataType.DATA_LOG);
                    dataTypeAndContent.setDataLog(log);// 与eqId无关放入最大队列
                    producer.sendSqlMessage(queueofsql - 1, producer.QUEUE_SQL, JSON.toJSONString(dataTypeAndContent));
                }
                // 插入控制类代码未定义后返回
                respBody.put("errorCode", 0);
                respBody.put("errorMsg", "");
                return;
                // 自动创建默认, 后台portal会自动生成
                /* 防止乱码，没有配置就不再处理
                f1.setDia_Rlt(faultCodes[k]);
                f1.setDia_Level(control56_fault_level);
                f1.setDia_Level_DH(control56_fault_leveldh);
                f1.setFault_Typ(faultCodes[k]); // 默认就是这个故障码
                f1.setM_Planning("");
                f1.setFaultclass(control56_fault_faultclass);
                f1.setRemark(control56_fault_remark);
                f1.setPartcode(control56_fault_partcode);
                 */
            }

            // 读取 故障分类： 扶梯设备、扶梯安全开关、直梯设备。从 control56config 查 bk1
            // 只有故障才需要
            control56.setBk4(null);
            if (f1 != null) {
                Control56config faultControl56config = PublicVars.getControl56config(control56configMappper, faultCodes[k]);
                if (faultControl56config != null) {
                    control56.setBk4(faultControl56config.getBk1());
                }
                control56.setBk1(f1.getFaultclass());
                // 统计次数理论上以 control56 最为准确。fault 增加了判断操作： 5分钟内，fault就不插入
                // 但是目前port还是 按 fault 来统计。
                if (!isControl56FaultRepeat(control56.getEquipmentid(), faultCodes[k])) {
                    saveFault4Control56(control56, f1, e1, faultCodes[k], false);
                    // 最后保存 : 将 Period 用作 Dia_Level，以方便定期清理数据
                    control56.setPeriod(f1.getDia_Level());
                } else {
                    saveFault4Control56(control56, f1, e1, faultCodes[k], true);
                }
                hasUpdatedLatestEquipmentStatus = true;
            }
        }
        saveControl56(control56, "FT");
        if (!hasUpdatedLatestEquipmentStatus) {
            updateLatestEquipmentStatusByControl56(control56, e1, "FT");
        }
    }

    // 直梯没有维保？
    private void ElevatorControl56(Control56 control56, Map respBody, Equipment e1) {
        // 维保判断用 -- 直梯不记录
        //        if (    isMaintainenceStatus.containsKey(control56.getEquipmentid())) {
        //            if ( !latestData_56Time.containsKey(control56.getEquipmentid())
        //                    ||  latestData_56Time.get(control56.getEquipmentid()).isBefore(control56.getTime()) )
        //                latestData_56Time.put(control56.getEquipmentid(), control56.getTime());
        //        }

        // 这几个字段收到的时候是NULL，先设置
        control56.setMqsendstatus(0);
        control56.setServersendstatus(0);
        control56.setEndtime(control56.getTime());
        control56.setPeriod(0); // 改为秒.默认20秒
        control56.setTotaltimes(1);

        // Hitachi 直梯特殊。
        // 状态码 ：状态点表40001(code1) ，楼层 40002(code2) ，故障码 40003(code3)
        // 故障码也是给出，详细故障码	电梯－>智能运维平台	AI	40003	0~7	16Bits	详见故障代码表2
        if (hitachiBrandid.equals(e1.getBrandid())
                && ("ZT".equalsIgnoreCase(e1.getBk2()))) {

            // Hitachi 有可能解析出这三个，要特殊处理，不能同时 STOP/UP/DOWN
            // HZ-1-1	状态	上行
            // HZ-1-2	状态	下行
            // HZ-1-3	状态	停止
            // 例如 code1 = 74  -- 1001010 --> HZ-1-1 HZ-1-3 HZ-1-6
            if(control56.getCode1() != null && (control56.getCode1() & 8) == 8 &&
                ((control56.getCode1() & 2) == 2 || (control56.getCode1() & 4) == 4)
            ) {
                control56.setCode6(control56.getCode1()); // 备查
                control56.setCode1(control56.getCode1() & 0b11110111);
            }

            Integer[] codes = new Integer[] {
                    control56.getCode1(),control56.getCode2(),control56.getCode3(),control56.getCode4(),control56.getCode5(),
                    control56.getCode6(),control56.getCode7(),control56.getCode8(),control56.getCode9(),control56.getCode10(),
                    control56.getCode11(),control56.getCode12(),control56.getCode13(),control56.getCode14(),control56.getCode15()
            };
            String[] statusFaultCode = PublicVars.getStatusCodeFaultCodeFromCode16(codes, brandIdBeginChars.get(e1.getBrandid()), control56configMappper, brandIdNumOfCodesZT.get(e1.getBrandid()), e1);
            if (statusFaultCode == null || statusFaultCode.length != 2) {
                control56.setStatuscode("0");
                control56.setFaultcode("0");
            } else {
                control56.setStatuscode(StringUtils.isEmpty(statusFaultCode[0]) ? "0" : statusFaultCode[0]);
                // 40003	0~7	16Bits	详见故障代码表2 HZ-3-数值
                if (control56.getCode3() == null || control56.getCode3() == 0) {
                    control56.setFaultcode("0");
                } else {
                    control56.setFaultcode(String.format("%sZ%s-3-%d"
                            , brandIdBeginChars.get(e1.getBrandid())
                            , StringUtils.isEmpty(e1.getBk80()) ? "" : e1.getBk80().trim()
                            , control56.getCode3()));
                }
            }
        } else {
            // 其他扶梯 + 直梯 ， 通过计算点位得到 : 确保 statusCode faultCode 不会是空
            Integer[] codes = new Integer[] {
                    control56.getCode1(),control56.getCode2(),control56.getCode3(),control56.getCode4(),control56.getCode5(),
                    control56.getCode6(),control56.getCode7(),control56.getCode8(),control56.getCode9(),control56.getCode10(),
                    control56.getCode11(),control56.getCode12(),control56.getCode13(),control56.getCode14(),control56.getCode15()
            };
            String[] statusFaultCode = PublicVars.getStatusCodeFaultCodeFromCode16(codes, brandIdBeginChars.get(e1.getBrandid()), control56configMappper, brandIdNumOfCodes.get(e1.getBrandid()), e1);
            if (statusFaultCode == null || statusFaultCode.length != 2) {
                control56.setStatuscode("0");
                control56.setFaultcode("0");
            } else {
                control56.setStatuscode(StringUtils.isEmpty(statusFaultCode[0]) ? "0" : statusFaultCode[0]);
                // 40003	0~7	16Bits	详见故障代码表2 HZ-3-数值  --> 先抄日立的。等通力具体再确定
                if (control56.getCode3() == null || control56.getCode3() == 0) {
                    control56.setFaultcode("0");
                } else {
                    control56.setFaultcode(String.format("%sZ%s-3-%d"
                            , brandIdBeginChars.get(e1.getBrandid())
                            , StringUtils.isEmpty(e1.getBk80()) ? "" : e1.getBk80().trim()
                            , control56.getCode3()));
                }
            }
        }

        //新增的 lineid, stationid, deptid, 根据Eq_id --> Station --> Line
        control56.setDataserverid(PublicVars.dataServerId);
        control56.setDataid(0L);

        // 维修状态不处理, 但是要记录，方便统计维保情况
        // isControl56Maintainence(control56, e1);

        // 需要进行合法性判断：所有合法的 controlcode, controlstatus都在 control56config 表中配置
        /* 先保存。以免客户端 deadloop
        Control56config statusControl56config = PublicVars.getControl56config(control56configMappper ,control56.getStatuscode().toString());
        if (statusControl56config == null){  // 搞不清，先判断 || !"状态".equalsIgnoreCase(statusControl56config.getControltype())
            throw new RuntimeException("服务器端control56config尚未配置该状态码");
        }
        Control56config faultControl56config = PublicVars.getControl56config(control56configMappper ,control56.getFaultcode());
        if (faultControl56config == null){
            throw new RuntimeException("服务器端control56config尚未配置该故障码");
        }
        */

        // 首先判断是否是需要统计的错误，如果是，插入fault...
        // 2023-05-21 点表-故障码可能多个
        String[] faultCodes = PublicVars.getArrayByString(control56.getFaultcode(), " ");
        boolean hasUpdatedLatestEquipmentStatus = false;
        for (int k = 0; k < faultCodes.length; k++) {
            if ("0".equalsIgnoreCase(faultCodes[k])) {
                continue;
            }
            FaultInfo f1 = PublicVars.getFaultinfo(faultInfoMapper, faultCodes[k]);
            // 如果状态码4 （故障），此时有可能故障码不存在。需要记录。同时还是需要生成fault数据
            // 控制板经常升级 -- 部分故障码可能没录入系统。---> 目前只有 HITACHI 才可能有这个情况。通力的没找到就不会写入了。
            if (f1 == null) {
                if (PublicVars.isPortalWithData == 1) {
                    DataLog log = new DataLog();
                    log.setCreate_time(LocalDateTime.now());
                    log.setDescription("控制类代码未定义");
                    log.setMethod(control56.getEquipmentid().toString());
                    log.setParams(faultCodes[k]);
                    log.setTime(1L);
                    log.setLog_type("FAULT");
                    log.setUsername("");
                    DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    log.setException_detail(dtf2.format(log.getCreate_time())); // recent time
                    // 2024-05-01 改为缓存
//                    if (dataLogMapper.update(log) <= 0) {
//                        dataLogMapper.insert(log);
//                    }
                    DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
                    dataTypeAndContent.setDataType(SQLDataType.DATA_LOG);
                    dataTypeAndContent.setDataLog(log);// 与eqId无关放入最大队列
                    producer.sendSqlMessage(queueofsql - 1, producer.QUEUE_SQL, JSON.toJSONString(dataTypeAndContent));
                }
                // 插入控制类代码未定义后返回
                respBody.put("errorCode", 0);
                respBody.put("errorMsg", "");
                return;
                // 自动创建默认, 后台portal会自动生成
                /* 防止乱码，没有配置就不再处理
                f1 = new FaultInfo();
                f1.setDia_Rlt(faultCodes[k]);
                f1.setDia_Level(control56_fault_level);
                f1.setDia_Level_DH(control56_fault_leveldh);
                f1.setFault_Typ(faultCodes[k]); // 默认就是这个故障码
                f1.setM_Planning("");
                f1.setFaultclass(control56_fault_faultclass);
                f1.setRemark(control56_fault_remark);
                f1.setPartcode(control56_fault_partcode);
                */
            }

            // 读取 故障分类： 扶梯设备、扶梯安全开关、直梯设备。从 control56config 查 bk1
            // 只有故障才需要
            control56.setBk4(null);
            if (f1 != null) {
                Control56config faultControl56config = PublicVars.getControl56config(control56configMappper, faultCodes[k]);
                if (faultControl56config != null) {
                    control56.setBk4(faultControl56config.getBk1());
                }
                control56.setBk1(f1.getFaultclass());
                // 统计次数理论上以 control56 最为准确。fault 增加了判断操作： 5分钟内，fault就不插入
                // 但是目前port还是 按 fault 来统计。
                if (!isControl56FaultRepeat(control56.getEquipmentid(), faultCodes[k])) {
                    saveFault4Control56(control56, f1, e1, faultCodes[k], false);
                    // 最后保存 : 将 Period 用作 Dia_Level，以方便定期清理数据
                    control56.setPeriod(f1.getDia_Level());
                } else {
                    saveFault4Control56(control56, f1, e1, faultCodes[k], true);
                }
                hasUpdatedLatestEquipmentStatus = true;
            }
        }
        //saveControl56(control56, "ZT");
        saveElevatorData(control56, e1, "ZT");
        if (!hasUpdatedLatestEquipmentStatus) {
            updateLatestEquipmentStatusByControl56(control56, e1, "ZT");
        }
    }
    /*
        public static final double BK4_LEVEL1_DATA = 0.0;
        public static final double BK4_LEVEL2_DATA = 1.0;
        public static final double BK4_LEVEL3_DATA = 2.0;
        public static final double BK4_LEVEL4_DATA = 3.0;
        public static final Double BK4_LEVEL9_DATA = 9.0;  //故障数据

        public static final Double BK1_NOT_KEEP_FILE = 0.0;
        public static final Double BK1_LEVEL1_FILE = 1.0;
        public static final Double BK1_LEVEL2_FILE = 2.0;
        public static final Double BK1_LEVEL3_FILE = 3.0;
        public static final Double BK1_LEVEL9_FILE = 9.0;  //故障数据对应文件
     */
    private void checkAndSetDataFileLevelTimes(SensorData sensorData1102) {
        if (sensorData1102 == null || sensorData1102.getEq_ID() == null || sensorData1102.getTime() == null) {
            return;
        }

        if (!dataFileLevelTimes.containsKey(sensorData1102.getEq_ID())) {
            List<EquipmentSensorDataFileLevelTime> datas = equipmentSensorDataFileLevelTimeMapper.getEquipmentSensorDataFileLevelTimesByEquipmentid(sensorData1102.getEq_ID());
            if (datas == null) {
                dataFileLevelTimes.put(sensorData1102.getEq_ID(), new ArrayList<>());
            } else {
                dataFileLevelTimes.put(sensorData1102.getEq_ID(), datas);
            }
        }
        List<EquipmentSensorDataFileLevelTime> oldDatas = dataFileLevelTimes.get(sensorData1102.getEq_ID());
        Double bk4 = sensorData1102.getBk4();
        if (!StringUtils.isEmpty(bk4)) {
            Integer iBk4 = bk4.intValue();
            if (iBk4 >= SensorData.iBK4_LEVEL2_DATA && iBk4 <= SensorData.iBK4_LEVEL4_DATA) {
                boolean hasData = false;
                for (EquipmentSensorDataFileLevelTime d : oldDatas) {
                    if (d.getDatafileflag() != null && d.getDatafileflag().equals(0)) { // data BK4
                        // Double[] levels = {SensorData.BK4_LEVEL2_DATA, SensorData.BK4_LEVEL3_DATA, SensorData.BK4_LEVEL4_DATA};
                        if (d.getDatafilelevel().equals(iBk4)) {
                            hasData = true;
                            if (sensorData1102.getTime().isAfter(d.getDatafiletime())) {
                                d.setDatafiletime(sensorData1102.getTime());
                                equipmentSensorDataFileLevelTimeMapper.updateDataFileTimeById(d);
                            }
                            break;
                        }
                    }
                }
                if (!hasData) {
                    EquipmentSensorDataFileLevelTime newData = new EquipmentSensorDataFileLevelTime();
                    newData.setEquipmentid(sensorData1102.getEq_ID());
                    newData.setDatafileflag(0);
                    newData.setDatafilelevel(iBk4);
                    newData.setDatafiletime(sensorData1102.getTime());
                    equipmentSensorDataFileLevelTimeMapper.insert(newData);
                    if (newData.getId() != null) {
                        oldDatas.add(newData);
                    } else {
                        dataFileLevelTimes.remove(sensorData1102.getEq_ID());
                    }
                }
            }
        }

        Double bk1 = sensorData1102.getBk1();
        if (!StringUtils.isEmpty(bk1)) {
            Integer iBk1 = bk1.intValue();
            boolean hasData = false;
            if (iBk1 >= SensorData.iBK1_LEVEL2_FILE && iBk1 <= SensorData.iBK1_LEVEL3_FILE) {
                for (EquipmentSensorDataFileLevelTime d : oldDatas) {
                    if (d.getDatafileflag() != null && d.getDatafileflag().equals(1)) { // file BK1
                        // Double[] fileLevels = {SensorData.BK1_LEVEL2_FILE, SensorData.BK1_LEVEL3_FILE};
                        if (d.getDatafilelevel().equals(iBk1)) {
                            hasData = true;
                            if (sensorData1102.getTime().isAfter(d.getDatafiletime())) {
                                d.setDatafiletime(sensorData1102.getTime());
                                equipmentSensorDataFileLevelTimeMapper.updateDataFileTimeById(d);
                            }
                            break;
                        }
                    }
                }
                if (!hasData) {
                    EquipmentSensorDataFileLevelTime newData = new EquipmentSensorDataFileLevelTime();
                    newData.setEquipmentid(sensorData1102.getEq_ID());
                    newData.setDatafileflag(1);
                    newData.setDatafilelevel(iBk1);
                    newData.setDatafiletime(sensorData1102.getTime());
                    equipmentSensorDataFileLevelTimeMapper.insert(newData);
                    if (newData.getId() != null) {
                        oldDatas.add(newData);
                    } else {
                        dataFileLevelTimes.remove(sensorData1102.getEq_ID());
                    }
                }
            }
        }
    }

    public Map<String, Long[]> listLastKeepDataTimeByEqId2023(int equipmentId) {
        if (!dataFileLevelTimes.containsKey(equipmentId)) {
            List<EquipmentSensorDataFileLevelTime> datas = equipmentSensorDataFileLevelTimeMapper.getEquipmentSensorDataFileLevelTimesByEquipmentid(equipmentId);
            if (datas == null) {
                dataFileLevelTimes.put(equipmentId, new ArrayList<>());
            } else {
                dataFileLevelTimes.put(equipmentId, datas);
            }
        }
        List<EquipmentSensorDataFileLevelTime> oldDatas = dataFileLevelTimes.get(equipmentId);
        Long[] dataTimestampList = new Long[]{null, null, null};
        Long[] fileDataTimestampList = new Long[]{null, null};
        if (oldDatas != null && !oldDatas.isEmpty()) {
            Integer[] levels = {SensorData.iBK4_LEVEL2_DATA, SensorData.iBK4_LEVEL3_DATA, SensorData.iBK4_LEVEL4_DATA};
            for (int i = levels.length - 1; i >= 0; i--) {
                // SensorData sensorData = sensorDataMapper.getLastSensorDataByLevel(equipmentId, PublicVars.sensorId4Level, levels[i]);
                EquipmentSensorDataFileLevelTime e = getByLevel(oldDatas, 0, levels[i]);
                setTimestamp(i, dataTimestampList, e);
            }

            Integer[] fileLevels = {SensorData.iBK1_LEVEL2_FILE, SensorData.iBK1_LEVEL3_FILE};
            for (int i = fileLevels.length - 1; i >= 0; i--) {
                //SensorData sensorData = sensorDataMapper.getLastSensorDataByFileLevel(equipmentId, PublicVars.sensorId4Level, fileLevels[i]);
                //setTimestamp(i, fileDataTimestampList, sensorData);
                EquipmentSensorDataFileLevelTime e = getByLevel(oldDatas, 1, fileLevels[i]);
                setTimestamp(i, fileDataTimestampList, e);
            }
        }
        Map<String, Long[]> result = new HashMap<>();
        result.put("data", dataTimestampList);
        result.put("file", fileDataTimestampList);
        return result;
    }
    private EquipmentSensorDataFileLevelTime getByLevel(List<EquipmentSensorDataFileLevelTime> oldDatas, Integer dataFileFlag, Integer dataFileLevel) {
        for (EquipmentSensorDataFileLevelTime e : oldDatas) {
            if (dataFileFlag.equals(e.getDatafileflag()) && dataFileLevel.equals(e.getDatafilelevel())) {
                return e;
            }
        }
        return null;
    }
    private void setTimestamp(int i, Long[] timestampList, EquipmentSensorDataFileLevelTime e) {
        ZoneOffset offset = CommonMethod.defaultOffset();
        Long timestamp = null;
        if (e != null && e.getDatafiletime() != null) {
            timestamp = e.getDatafiletime().toInstant(offset).toEpochMilli();
        }
        if (i == timestampList.length - 1) {
            timestampList[i] = timestamp;
            return;
        }
        if (timestamp == null) {
            timestampList[i] = timestampList[i + 1];
            return;
        }
        if (timestampList[i + 1] == null) {
            timestampList[i] = timestamp;
            return;
        }
        timestampList[i] = Math.max(timestamp, timestampList[i + 1]);
    }

    private void sendRms1601(Integer equipmentid, Double rms1601) {
        if (web56 == 1) {
            Control56SmallDTO control56SmallDTO = new Control56SmallDTO();
            control56SmallDTO.setEquipmentid(equipmentid);
            control56SmallDTO.setRms1601((long)Math.round(rms1601) + "");

            Latest56AndEqf2Web.save1601(control56SmallDTO);

            /* 改 ws 发送
            SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
            requestFactory.setConnectTimeout(30000); //设置超时
            requestFactory.setReadTimeout(60000);
            RestTemplate restTemplate = new RestTemplate(requestFactory);
            //RestTemplate restTemplate = new RestTemplate();
            String url = PublicVars.serverBaseUrl + "/rms1601InMemory";
            try {
                restTemplate.put(url, control56SmallDTO);
            } catch (Exception e) {
                e.printStackTrace();
            }
            */
            // log.info(url);
        }
    }
    private void sendSlowRunOrStop(Integer equipmentid, Integer status) {
        if (web56 == 1 && (equipmentid != null && status != null) && (status == 4 || status == 5)) {
            Latest56AndEqf2Web.saveSlowRunOrStop(equipmentid, status);
            /* 改 ws 发送
            SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
            requestFactory.setConnectTimeout(30000); //设置超时
            requestFactory.setReadTimeout(60000);
            RestTemplate restTemplate = new RestTemplate(requestFactory);
            //RestTemplate restTemplate = new RestTemplate();
            String url = String.format("%s/slowRunOrStopInMemory/%d/%d",PublicVars.serverBaseUrl , equipmentid, status);
            try {
                restTemplate.put(url, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            // log.info(url);
             */
        }
    }

    private void updateLatestEquipmentStatusByControl56(Fault fault) {
        if (fault == null || fault.getDialevel() == null || fault.getDialevel() <= 0 || fault.getDialevel() >= 4) {
            return;
        }
        LatestSensorStatusData.hasControl56Fault.put(fault.getEq_ID(), 1); // 进入这里表示有B类故障
        LatestSensorStatusData.latest56Fault.put(fault.getEq_ID(), fault);

        EquipmentStatus equipmentStatus = new EquipmentStatus();
        equipmentStatus.setLineid(fault.getLineid());
        equipmentStatus.setStation_ID(fault.getStation_ID());
        equipmentStatus.setEq_ID(fault.getEq_ID());
        equipmentStatus.setBk1(fault.getBk1());
        equipmentStatus.setBk2(fault.getBk2());
        equipmentStatus.setBk4(fault.getBk4());
        equipmentStatus.setBk5(fault.getBk5());
        equipmentStatus.setDataId(fault.getDataId());
        equipmentStatus.setDeptid(fault.getDeptid());
        equipmentStatus.setBrandid(fault.getEquipmentbrandid());
        equipmentStatus.setStatus(fault.getDialevel());
        equipmentStatus.setTime(fault.getTime());
        equipmentStatus.setEndTime(fault.getEndTime());
        equipmentStatus.setMQ_Send_Status(0);
        equipmentStatus.setServer_Send_Status(0);
        equipmentStatus.setPeriod(fault.getPeriod());
        equipmentStatus.setTotalTimes(fault.getTotalTimes());
        // 2024-05-01 改为缓存
        //        if (latestEquipmentStatusDao.update(equipmentStatus) <= 0) {
        //            latestEquipmentStatusDao.insert(equipmentStatus);
        //        }

        equipmentStatus.setIsSync(fault.getDialevel());
        equipmentStatus.setSyncTime(fault.getTime());
        equipmentStatus.setBk1id(fault.getDialevel());
        equipmentStatus.setStatus(LatestSensorStatusData.convert2Status(equipmentStatus.getBk1id()));
        equipmentStatus.setBk2id((long)LatestSensorStatusData.BJFAULT);

        DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
        dataTypeAndContent.setDataType(SQLDataType.LATEST_EQUIPMENT_STATUS);
        dataTypeAndContent.setEquipmentStatus(equipmentStatus);
        producer.sendSqlMessage(equipmentStatus.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));
    }

    private void updateLatestEquipmentStatusByControl56(Control56 control56, Equipment e, String type) {
        if (control56 == null || e == null) {
            return;
        }
        LatestSensorStatusData.hasControl56Fault.put(control56.getEquipmentid(), 0); // 进入这里表示没有B类故障
        LatestSensorStatusData.latest56Fault.remove(control56.getEquipmentid());

        EquipmentStatus equipmentStatus = new EquipmentStatus();
        equipmentStatus.setLineid(control56.getLineid());
        equipmentStatus.setStation_ID(control56.getStationid());
        equipmentStatus.setEq_ID(control56.getEquipmentid());
        equipmentStatus.setBk1(control56.getBk1());
        equipmentStatus.setBk2(control56.getBk2());
        equipmentStatus.setBk4(control56.getBk4());
        equipmentStatus.setBk5(control56.getBk5());
        equipmentStatus.setDataId(control56.getDataid());
        equipmentStatus.setDeptid(control56.getDeptid());
        equipmentStatus.setBrandid(e.getBrandid());

        if ("ZT".equalsIgnoreCase(type)) {
            // 由于直梯状态码唯一，not like 扶梯有简单的 2、3等，因此只需要用 indexOf包含比较
            String[] statusCodes = control56.getStatuscode() == null ? null : control56.getStatuscode().split(" ");
            Integer statusup = checkElevatorStatus("up", statusCodes);
            Integer statusdown = checkElevatorStatus("down", statusCodes);
            // Integer statusstop = checkElevatorStatus("stop", statusCodes);
            equipmentStatus.setStatus(statusup + statusdown == 0 ? 5 : 0);
        } else if ("FT".equalsIgnoreCase(type)) {
            if (StringUtils.isEmpty(control56.getStatuscode())) {
                return;
            }
            Set<String> statusCodes = PublicVars.getSetByString(control56.getStatuscode(), " ");
            //            String normalStopCode = brandIdNormalStopCodes.getOrDefault(e.getBrandid(), "XNULL");
            //            equipmentStatus.setStatus(statusCodes.contains(normalStopCode) ? 5 : 0);
            Set<String> normalStopCode = brandIdNormalStopCodes.getOrDefault(e.getBrandid(), Collections.EMPTY_SET);
            equipmentStatus.setStatus(PublicVars.contails(normalStopCode, statusCodes) ? 5 : 0);
        } else {
            return;
        }

        equipmentStatus.setTime(control56.getTime());
        equipmentStatus.setEndTime(control56.getTime());
        equipmentStatus.setMQ_Send_Status(0);
        equipmentStatus.setServer_Send_Status(0);
        equipmentStatus.setPeriod(control56.getPeriod());
        equipmentStatus.setTotalTimes(1);
        // 2024-05-01 改为缓存
        //        if (latestEquipmentStatusDao.update(equipmentStatus) <= 0) {
        //            latestEquipmentStatusDao.insert(equipmentStatus);
        //        }

        // 上下行 停止 维保
        equipmentStatus.setBk2id(LatestSensorStatusData.checkUpDownWeibaoStop(control56, e));
        if (LatestSensorStatusData.BJWEIBAO == equipmentStatus.getBk2id()) {
            equipmentStatus.setStatus(5);
            equipmentStatus.setBk1id(LatestSensorStatusData.BJWEIBAO);
            equipmentStatus.setIsSync(LatestSensorStatusData.BJWEIBAO);
            equipmentStatus.setSyncTime(control56.getTime());
//        } else if (LatestSensorStatusData.BJFAULT == equipmentStatus.getBk2id()) { 这个是故障的分支。
//            equipmentStatus.setStatus(0);
//            equipmentStatus.setBk1id(0);
//            equipmentStatus.setIsSync(0);
//            equipmentStatus.setSyncTime(control56.getTime());
        } else if (LatestSensorStatusData.BJSTOP == equipmentStatus.getBk2id()) { // 新的停止代码
            equipmentStatus.setStatus(5);
            equipmentStatus.setBk1id(LatestSensorStatusData.BJSTOP);
            equipmentStatus.setIsSync(LatestSensorStatusData.BJSTOP);
            equipmentStatus.setSyncTime(control56.getTime());
        } else {
            equipmentStatus.setStatus(0);
            equipmentStatus.setBk1id(0);
            equipmentStatus.setIsSync(0);
            equipmentStatus.setSyncTime(control56.getTime());
        }

        DataTypeAndContent dataTypeAndContent = new DataTypeAndContent();
        dataTypeAndContent.setDataType(SQLDataType.LATEST_EQUIPMENT_STATUS);
        dataTypeAndContent.setEquipmentStatus(equipmentStatus);
        producer.sendSqlMessage(equipmentStatus.getEq_ID() % queueofsqlfirst, producer.FIRST_SQL, JSON.toJSONString(dataTypeAndContent));
    }
    @GetMapping("/testemail/{eqId}/{diarlt}/{isnew}")
    public String testemail(@PathVariable("eqId") Integer eqId, @PathVariable("diarlt") String diarlt, @PathVariable("isnew") Integer isnew) {
        EmailData emailData = new EmailData();
        emailData.setDataType(1);
        emailData.setEqId(eqId);
        emailData.setDiaRlt(diarlt);
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        emailData.setFaultTime(dtf2.format(LocalDateTime.now()));
        emailData.setIsNewFault(isnew);

        EmailDatalList.emailDatas.add(emailData);

        return JSON.toJSONString(emailData);
    }
    //工控机
    @PostMapping("/synctime")
    public String synctime() {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return dtf.format(LocalDateTime.now());
    }

    @GetMapping("/upgradelog/{equipmentid}")
    public String getUpgradeLog(@PathVariable("equipmentid") Integer equipmentid) {
        List<UpgradeLog> upgradeLogs = upgradeLogMapper.getUpgradeLog(equipmentid);
        if (upgradeLogs == null || upgradeLogs.isEmpty()) {
            return String.format("No data: %d @ %s", equipmentid, LocalDateTime.now().toString());
        }
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        StringBuffer ret = new StringBuffer();
        for (int i = 0; i < upgradeLogs.size(); i++) {
            String log = String.format("[ id : %d, create_time : %s, eqid : %d, makedate : %s, paramtype : %s, programtype : %s, params : %s ]",
                    upgradeLogs.get(i).getId(),dateTimeFormatter.format(upgradeLogs.get(i).getCreate_time()),
                    upgradeLogs.get(i).getEquipmentid(), upgradeLogs.get(i).getMakedate(), upgradeLogs.get(i).getParamtype(),
                    upgradeLogs.get(i).getProgramtype(), upgradeLogs.get(i).getParams());
            ret.append(log);
        }
        return ret.toString();
    }
}
